Skip to main content

Inflight Magazine no. 3

Β· 13 min read
Chris Rybicki

The 3rd issue of the Wing Inflight Magazine.

Hey everyone!

We're delighted to share with you the third ever issue of the Wing Inflight Magazine (here's a link to our last issue if you missed it).

The Inflight Magazine is where you can stay up to date with Wing Programming Language developments, community events, and all things Wing.

Have comments or questions about Wing? Hit us up at @winglangio on Twitter or leave a message in our Slack!

This week's cloud computing joke...

Q: Why do serverless developers make terrible comedians?

A: Because their jokes always end up with a cold start!

TL;DR​

Here is a summary of the topics in today's issue:

TS;GMM (too short; give me more)​

Check out the latest Wingly Update episode​

The Wingly Update is our biweekly show where we stream to Twitch, share the latest developments of the project, and just make a bunch of fools of ourselves.

In our last show, Eyal hosted Shai, Elad, Mark the DJ, and a special guest, Eric Johnson, who is an AWS developer advocate and Wing enthusiast.

Here are some of the topics we covered:

  • Defining API endpoints in Wing
  • Introducing the Redis resource
  • Running tests in the cloud
  • Q&A with Eric Johnson about serverless and Wing

If you didn’t get a chance to catch it live, you can tune in here and check out our next shows on Twitch.

The first Wing hackathon has completed!​

We're excited to share that we just finished the first-ever Wing hackathon, known as the Wingathon! The hackathon took place over the last two weeks, and we had a blast seeing all the cool projects that were submitted.

The goal of this hackathon was simple -- to push the boundaries of creativity and innovation by using Wing and its existing surface area to create a working system that is ready for actual use. We evaluated the projects based on whether they worked in a live cloud, how much of the project code was written in "pure" Wing, and the project's coolness factor. And we were blown away by the results!

Some of the projects that were submitted include:

  • Publication ETL - an extract-transform-load system that listens for XML documents uplaoded to an S3 bucket, normalizes the documents, and loads them into a database for downstream use (by Hasan Abu-Rayyan and Cristian PallarΓ©s)
  • Flight controller - a task orchestration system that takes user-defined tasks and send them for executions with specified concurrency limits (by EJ Wang)
  • Where to eat - a web app that shows restaurants aroud you, and allows you to bookmark your favorite restaurants (by Uri Bar and Shai Ainover)

The winning project was What happened today? by Raphael Manke - a slack bot that lets you enter slash commands to return a list of all commits made to a GitHub repository since the user last checked. Awesome job, Raphael!

Check out the Wing research repo to see the project's source code, or join our Slack to get notified when we announce the next Wingathon.

Community support for AWS CDK target introduced​

Thanks to the efforts of Marcio, we now have community support for the AWS CDK target in Wing! This means you run wing compile --target=awscdk and get a CDK application that you can deploy to AWS using CloudFormation. Here's an example of a Wing app that uses the AWS CDK target:

bring cloud;
bring "aws-cdk-lib" as aws;

let queue = new cloud.Queue();
let bucket = new cloud.Bucket();

queue.addConsumer(inflight (message: str) => {
bucket.put("latest_message.txt", message);
});

let func = new cloud.Function(inflight () => {
queue.push("hello world!");
});

let table = new aws.awsDynamodb.Table();

As you can see, several resources from our batteries-included SDK are available in the AWS CDK target. Whenever you use these resources, your app can be deployed both to AWS using CloudFormation or to the Wing simulator.

Since we are compiling to AWS CDK, we are also able to use any constructs from aws-cdk-lib directly in Wing. Since these imported resources don't know anything about Wing's "inflights", IAM permissions for these resources can't be inferred automatically by the compiler, and they can't do a thing in the Wing simulator. But it's still possible to define permissions explicitly using AWS CDK APIs, and in the future we're planning to add mechanisms to specify how foreign resources behave in the simulator.

Try it out and let us know what you think! Huge thanks again to Marcio for adding support for this feature!

Extern functions - call out to JavaScript straight from Wing​

A common ask from developers we talk to (and our own team) has been -- if Wing is able to compile applications down to JavaScript (and it is!), how can we reuse existing JavaScript code and libraries in Wing apps?

The answer is extern functions. Extern functions let you specify a function is not implemented in Wing, but by a piece of external JavaScript. Here's an example - let's say we have a file called helpers.js that contains the following code that generates unique IDs for us:

const uuid = require("uuid");

exports.makeId = async function() {
return uuid.v4();
}

(In order for this to work, you'll also need to run npm install uuid in the same directory as helpers.js).

We can then use this function in our Wing app as if it were a regular Wing function:

bring cloud;

resource Utils {
init() {}
// define the extern function here...
extern "./helpers.js" inflight makeId(): str;
}

let bucket = new cloud.Bucket();
let utils = new Utils();

new cloud.Function(inflight () => {
// ...and use it inflight here
let id = utils.makeId();
bucket.put(id, "hello world!");
}) as "test";

If you simulate the app locally using the Wing Console, your development machine will call the makeId function in helpers.js and use the copy of uuid you already have installed when simulating cloud.Function.

But if you compile the app to the tf-aws target, Wing will bundle all of your code -- including the uuid dependency -- into a single AWS Lambda function, so that the code will work the same way in the cloud as it does in the simulator.

Extern code is necessarily unsafe -- Wing can't guarantee the function will behave the same way in the simulator as it does in the cloud. But we think it will be possible to create safe and reusable abstractions around extern functions in Wing, and we're excited to see what you build with it!

Test in the cloud and in the Wing Console​

Preventing bugs is one of the most important parts of writing production-quality code. That's why Wing has a built-in simulator that lets you test your app locally before deploying it to the cloud. We think this is a great way to stay in the flow while iterating on your code.

But beyond that, we know it's important to be able to test your app in the cloud as well. After all, how do you know for sure that your app doesn't hit against some AWS service limit, or that it doesn't have a bug that only manifests itself in the cloud?

That's why Wing has a built-in testing mechanism, that we've expanded to support testing your app in the cloud as well. Let's first recap how unit tests work in Wing. Here's an app that manages a list of tasks using a bucket and a counter:

// task_list.w
bring cloud;

resource TaskList {
data: cloud.Bucket;
counter: cloud.Counter;
init() {
this.data = new cloud.Bucket();
this.counter = new cloud.Counter();
}

inflight addTask(title: str): str {
let id = "task-${this.counter.inc()}";
this.data.put(id, title);
return id;
}

inflight getTask(id: str): str {
let title = this.data.get(id);
return title;
}
}

To write tests for this app, we can simply create new cloud.Function's whose resource id's start with test or test:

// task_list.w (extended)
let taskList = new TaskList();

new cloud.Function(inflight () => {
let id1 = taskList.addTask("get avocados");
let id2 = taskList.addTask("walk my cat");
assert(id1 != id2);
}) as "test:add multiple tasks";

new cloud.Function(inflight () => {
let id = taskList.addTask("buy a new hat");
let result = taskList.getTask(id);
assert(result == "buy a new hat");
}) as "test:add and get task";

Thanks to recent work by our amazing console team, if we open the Wing Console with wing it task_list.w, we're now able to run the tests against the Wing simulator using the new testing panel:

Before runningAfter running
testing-paneltesting-panel-success

By the way, did we mention the Wing Console now has a dark mode? πŸŒ™

But we can also run the tests in the cloud by using the --target flag on the wing test CLI command. For example, to run the tests in AWS, we can run wing test --target tf-aws task_list.w:

$ wing test -t tf-aws hello.w
βœ” Compiling to tf-aws...
βœ” terraform init
βœ” terraform apply
βœ” Setting up test runner...
βœ” Running tests...
pass ─ hello.tfaws Β» root/Default/env0/test:add multiple tasks
pass ─ hello.tfaws Β» root/Default/env1/test:add and get task
βœ” terraform destroy

How cool is that? Now you can test your app in the cloud as well as in the simulator, all from the comfort of your terminal.

There is still a lot of work ahead of us - so far we only support cloud tests on AWS, so we would like to support more cloud providers. But we would like to make it easier to view logs from your tests, and to debug your app when tests fail. We're excited to see what you build with this new feature!

New SDK resources and methods​

Wing's standard library of resources is rapidly growing! Here are the latest additions:

cloud.Api​

This is your bread-and-butter API gateway resource that lets you create HTTP endpoints for your Wing app. Endpoints are one of the easiest ways to expose your Wing app to the outside world, and they are also a great way to test your app locally using the Wing Console. You can define routes and methods, and each route can have a handler function that will be called when a request is received. Here's an example:

bring cloud;

let api = new cloud.Api();
api.get("/hello", inflight (req: cloud.ApiRequest): cloud.ApiResponse => {
return cloud.ApiResponse {
body: Json { message: "Hello, world!" },
status: 200,
};
});

The API resource highlights our design philosophy of making it easy to write code that works both in the cloud and in the simulator, through the use of cloud-agnostic APIs.

So far we've added support for this resource on both the tf-aws and sim targets. When you compile to AWS, this will produce an AWS API Gateway that exposes the endpoints on the public internet -- and when you compile to the simulator, you'll get a local HTTP server that you can interact with using the Wing Console, or any other HTTP client like curl or Postman.

Shout out to Raphael for adding support for cloud.Api on AWS! Check out our API Reference for more details (docs with examples coming soon), and give us a +1 on any of these issues if you would like support for cloud.Api on GCP, Azure, or if you'd like to see a dedicated cloud.GraphQL resource!

cloud.Bucket events​

Acting on events is a great way to build reactive applications that leverage the cloud's scalability.

Wing's cloud.Bucket resource now supports the following events that allow you to run an inflight function when a certain event occurs:

  • onCreate - triggered when a new object is added to the bucket
  • onDelete - triggered when an object is deleted from the bucket
  • onUpdate - triggered when an object is updated in the bucket
  • onEvent - triggered when any of the above events occur

Here's an example of how you can use these events to count the number of objects added to a bucket, and expose that count through an API endpoint:

bring cloud;

let bucket = new cloud.Bucket();
let counter = new cloud.Counter();

bucket.onCreate(inflight (key: str) => {
log(key);
counter.inc();
});

let api = new cloud.Api();
api.get("/count", inflight (req: cloud.ApiRequest): cloud.ApiResponse => {
return cloud.ApiResponse {
body: Json { objectsAdded: counter.peek() },
status: 200,
};
});

Potpourri of new resources and methods​

We've got too many new resources and additions to list them all here, but here are some of the highlights:

  • cloud.Table - a NoSQL table that can be used to statefully manage structured information supports basic CRUD operations. Currently supported on the sim and tf-aws targets. (Note: as databases are hard to abstract, this resource is highly experimental right now and is likely to change in the future.)
  • cloud.Secret - a key-value store that can be used to store sensitive information like passwords and API keys. Currently supported on the sim, tf-aws and awscdk targets.
  • redis.Redis - a Redis instance that can be used to store unstructured data. Currently supported on the sim and tf-aws targets. When you compile to AWS, this will create a Redis instance in ElastiCache hosted in its own VPC, with a security group that only allows access from the VPC that your Wing app is running in. When you compile to the simulator, this resource will use Docker to run a local Redis instance.

Lastly, we also want to bring to everyone's attention that the built-in print() function is now named log(). This is a breaking change, but we think it's a meaningful one.

print() is a very common function name in programming languages, and we wanted to make it clearer that when you're writing an application where the cloud is your computer, log() has a specific intent that's distinct from emitting text to a standard output stream. For example, logs are often aggregated in a centralized logging service like Datadog or Papertrail, and there isn't a distinction between logging with or without a newline in the cloud.

But we also acknowledge that naming things is hard! So if you have any thoughts on this, please let us know!

Thanking our contributors​

We appreciate everyone who has contributed fixes, features, and documentation to Wing since the last issue: @Raphael Manke, @Marcio Cruz, @Jake Page, @Yariv Levy, @EJ Wang, @davidnx, @Fynn FlΓΌgge, @Gary Sassano, and @Ananthu C V.

Summary​

As usual, we can't wait for you to board our adventure to transform the cloud into the ultimate software-building playground. You'll find us regularly mingling on Slack, so feel free to introduce yourself, and if you haven't yet, give winglang.io a visit and take Wing out for a spin.

See you in our next flight!