Inflight Magazine no. 8
import ReactPlayer from "react-player"; import console_new_look from "./assets/2024-03-13-magazine-008/console-new-look.mp4";
The 8th issue of the Wing Inflight Magazine.
Hello Wingnuts!
We are back with another issue of the Wing Inflight Magazine and excited to share some updates about Winglang, an open source-programming language for the cloud.
Wing is shipped with a powerful cloud simulator which allows developers to write and test complete cloud application without having to deploy anything to the cloud.
The language combines cloud infrastructure and runtime into a single programming model and compiles to Terraform/CloudFormation and JavaScript that are ready to deploy to AWS, GCP and Azure (see support matrix).
We are designing Wing to be familiar and friendly for developers who come from modern object-oriented background, so it will take you 5 minutes to learn.
Check out our getting started tutorial or hit the Wing Playground for an online experience.
In today's issueβ
- π Deploying AWS resources and APIs inside a private VPCs
- π¨ A fresh look for the Wing Console map view
- π€© New syntax for creating sets
- π₯ Mutually referential type declarations
- π The bang
!
operator - ποΈ Ability to lift collection of inflight closures
- ποΈ
fs.appendFile()
- β Platform Parameters and AWS VPC configuration
- π Ergonomic improvements for
cloud.Function
andcloud.Api
- π₯ Goodies from the Wingly Update
- π―ββοΈ Community Events
NOTE: I spent like two hours trying to figure out the right emojis here so please take a minute to appreciate them :-)
Deploying AWS resources and APIs inside a private VPCsβ
Users tell us they are looking for ways to deploy API-based services inside their VPCs. We've spent some time learning about the challenges people have and figured we can offer a awesome experience in Wing for this use case.
We published a guide which describes how to configure the tf-aws
platform to deploy your application's AWS resources and APIs inside a VPC, with support for creating a whole new VPC or deploying into a VPC that's already setup in your environment.
Check out a recording of this online workshop by Hasan Abu-Rayyan from the Wing core team, where he talks about this use case and walks through an example.
Ruslan Kazakov from Sydney, Australia wrote about his experience in a blog post :
βWing made all the difference! After struggling for days with the CDK, I turned to Wing and had a fully functional Private API Gateway up and running within hours. Its simplicity and power are unparalleled. Thank you, Wing, for saving me time and headaches!β
A fresh look for the Wing Console map viewβ
We gave the map view in Wing Console some love, improved colors, cleaned up the UI and polished the interactions:
New syntax for creating setsβ
Wing has a built-in Set
type to represent a collection of unique values. This type used to have its own literal syntax which used curly braces {}
:
let mySet = {1, 2, 3}; // before
While this syntax was cute, it caused some confusion with the object literal syntax that also uses curly braces ({ foo: 123 }
). Given how infrequently sets are created (and how frequently object literals are used), the syntactic complexity seemed unwarranted. Sets can now be created with the existing square brackets []
alongside a type annotation:
let mySet = Set<num> [1, 2, 3];
Mutually referential type declarationsβ
It is now possible for two type declarations such as struct
s, interface
s, or class
es to refer to each other:
interface IThing1 {
m2(): IThing2;
}
interface IThing2 {
m1(): IThing1;
}
struct M1 { m2: M2?; }
struct M2 { m1: M1?; }
This implies that declarations can be used anywhere within the scope, regardless of where they are located in the file. Declarations are basically type system information and they are not executed, so there is no meaning to their order.
// this works even though M1 is declared later!
let x: M1 = {};
struct M1 { m2: M2?; }
struct M2 { m1: M1?; }
The bang !
operatorβ
We are continuing to add language tools for safely dealing with nullity.
The bang operator (!
) performs a runtime assertion that a value is not nil
, and returns the value.
An error will be thrown if the value is nil
. Unlike TypeScript, where !
is only a type-checking hint, in Wing the bang operator will actually throw an error if there is no value. This means that nullity will not propagate further and avoids the common horrors of "Cannot read properties of undefined"
errors, cascading through your program.
struct User {
name: str;
email: str;
}
let response = http.get("https://api.mysystem.com/users/127364");
let user = User.parseJson(response.body!); // since "body" is `str?` we need to unwrap it
log("name: {user.name}, email: {user.email}");
This is roughly equivalent to:
if let body = response.body {
let user = User.parseJson(body);
// ...
} else {
throw "Unexpected nil";
}
Ability to lift collection of inflight closuresβ
This is a very powerful addition to the Wing lifting system that opens up many interesting use cases.
It is now possible to lift collections of inflight closures (arrays, maps, etc) from preflight to inflight. This allows you to collect them during preflight and execute later. For example, a common use case is event handlers.
The example below implements a simple pub/sub mechanism using a collection of inflight closure. The Users
class which allows consumers to subscribe to a "sign up" event by providing an inflight closure as the handler. When a new user signs up, all the handlers are called:
bring cloud;
class Users {
signupHandlers: MutArray<inflight (str): void>;
new() {
this.signupHandlers = MutArray<inflight (str): void>[];
}
pub onSignup(handler: inflight (str): void) {
this.signupHandlers.push(handler);
nodeof(this).addConnection(name: "onSignup", source: unsafeCast(handler), target: this);
}
pub inflight signup(user: str) {
for h in this.signupHandlers {
h(user);
}
}
}
class UserCounter {
counter: cloud.Counter;
new(users: Users) {
this.counter = new cloud.Counter();
users.onSignup(inflight () => {
this.counter.inc();
});
}
pub inflight count(): num {
return this.counter.peek();
}
}
class WelcomeEmail {
new(users: Users) {
users.onSignup(inflight (email) => {
// send an email to user
});
}
}
let users = new Users();
new UserCounter(users);
new WelcomeEmail(users);
Notice the cool usage of nodeof(x).addConnection()
which results in this beautiful view:
fs.appendFile()
β
A new function on the filesystem (fs
) builtin module. fs.appendFile()
writes data to the end of a file.
bring fs;
let file = "/dummy.txt";
fs.writeFile(file, "Hello ");
fs.appendFile(file, "World!");
// file now contains "Hello World!"
Platform Parameters and AWS VPC configurationβ
Platforms are the "backend" of the Wing compiler. They hook into the compilation and synthesis process and determine everything about how an app will eventually be deployed to the cloud. Wing is shipped with a set of built-in platforms such as tf-aws
, tf-azure
, but users can create their own platform extensions, and we are starting to see some very creative and powerful capabilities enabled by this feature.
It is now possible for platforms to read parameters from a configuration file (wing.toml
) or from the -v
CLI switch.
As one example of this, the tf-aws
platform now supports a few parameters related to handling VPCs. The parameters provide an easy mechanism to control this cross-cutting concern across all your resources:
wing.toml
:
[tf-aws]
vpc = "existing"
vpc_id = "vpc-088c31249bb80726a"
vpc_lambda = true
With the above configuration, when compiling the following program to tf-aws
, the AWS Lambda function below will be placed inside an existing VPC:
bring cloud;
new cloud.Function(inflight () => {
log("hi");
});
Ergonomic improvements for cloud.Function
and cloud.Api
β
cloud.Function
and cloud.Api
are fundamental building blocks of Wing's SDK. They both make use of inflight handlers for their runtime.
These handlers had a required return type, which was often not actually needed. Now this return type is optional and defaults to a sensible value:
new cloud.Function(inflight (event) => {
log(event);
// no need to return anything!
})
new cloud.Api().post("/", inflight () => {
log("Hi");
// can also return a partial response with no body, like:
// return { status: 200 };
})
Invoking cloud.Function
also now has an optional argument instead of a required one:
let func = new cloud.Function(inflight () => {
log("Hi");
});
test "invoke function" {
func.invoke();
}
Goodies from the Wingly Updateβ
The Wingly Update is our corky bi-weekly stream where we share the latest developments of the project, chat with folks from the cloud industry, geek out and celebrate the beauty of the cloud.
If you haven't been able to catch our show, you can find the complete stack of all our episodes here.
Here are a few goodies we curated from recent shows:
- Huzaifa Asif came to chat with us about his career journey and his new book Designing Scalable Systems.
- Live Hacking Session Building a Slack Bot - the first in a series of sessions where we build a Slack bot with Wing.
Community Eventsβ
You can find details for all our events in the Wingnuts Calendar, amongst them:
- Winglang Community Meeting is our bi-weekly gathering where members of our community showcase cool apps, demos, and other projects! The upcoming session is scheduled for Tuesday, December 19th, at 2:30 PM UTC. We look forward to seeing you there!
- Monday Office Hours is our bi-weekly opportunity for you to share your feedback, thoughts, concerns, or simply drop by to say hi.
Summaryβ
That's it for this edition!
You are invited to join the Wing Discord! Come say hello and hang out with fellow Wingnuts! Give winglang.io a visit and take Wing out for a spin. If you're not already, stay updated on the latest changes in our repo.
Catch you in the next update!
The Wing Team