10 easy Steps to create AWS Lambda functions with the Serverless Framework & Reason in AWS Cloud9

K - Dec 5 '17 - - Dev Community

Cover image by Kyle James on Flicker.

After reading this awesome tutorial by Daniel Golant, I tried myself at AWS Lambda. To make the whole thing a bit more interesting than just using the Serverless Framework with Node.js instead of Python, I added AWS Cloud9 and Reason to the mix.

What are we working with?

There is a new online IDE called AWS Cloud9. Runs on EC2 and comes with many dev tools.

AWS Lambda is a good bit older, it's a way to run functions you code in the cloud without messing with servers. AWS just starts copies of them when you get more users.

The serverless framework is a way to make AWS Lambda more accessible, because the regular way to work with it is kind of a pain.

Reason is a language created by Facebook. With the BuckleScript compiler, which is a backend for the OCaml compiler, Reason is compiled to JavaScript. It's basically OCaml with a JavaScript like syntax.

What needs to be done?

  1. Setting up an AWS account
  2. Adding an IAM user to the account
  3. Adding permissions for Cloud9 and administration to that user
  4. Logging into AWS with the created user
  5. Creating a Cloud9 environment
  6. Installing and configuring BuckleScript
  7. Installing and configuring Serverless
  8. Converting the JavaScript code to Reason
  9. Compiling Reason to JavaScript
  10. Deploying function to AWS Lambda

How

1. Setting up an AWS account

First we need an AWS account to get access to the services we want to use.

You can create one here

As you can see, 12 months of free usage are included. As long as you use the services that are elegible for the free tier you are good to go.

2. Adding an IAM user to the account

Next is setting up an IAM user, so you can access the services without using your root account.

For this, you first need to login into the AWS Management Console

Top left is a Services menu, where you choose IAM from the Security, Identity & Compliance category.

Click on Users on the left and choose Add User.

Give it a name you can remember, preferably lower-case, also give it programmatical access, which is used by the serverless framework later. Also AWS Management Console access so you can login with a password to create your Cloud9 environment.

Then hit Next: Permissions

3. Adding permissions for Cloud9 and administration to that user

Choose Attach existing policies directly.

Here you have to search for the AdministratorAccess and AWSCloud9User permissions and check them.

The first is needed by the serverless framework, the second, you guessed it, by Cloud9.

Now you can go to Review to check if everything is alright and then Complete.

If you used an auto-generated password it will be shown in the Complete screen, you have to save it for login.

Close this wizard, you should now see a list of users. Click on the username of your new user.

Click on the tab Security Credentials, this gives you a Console login link, save it.

Then sign out.

4. Logging into AWS with the created user

Now try to login to the AWS Management Console with the Console Login Link you saved.

It should look like this:

https://<NUMBER>.signin.aws.amazon.com/console
Enter fullscreen mode Exit fullscreen mode

Enter the username and the password of your new user and login.

5. Creating a Cloud9 environment

Open the Services menu on the top left and select Cloud9 in the Developer Tools category.

Here is a button create environment you have to click.

Give it a name and do the Next step

The configure settings can be left as they are, just the Instance type needs to be change from t2.micro to t2.small, because BuckleScript will compile the OCaml compiler, which takes more than 1GB memory. We will set it back at the end of the BuckleScript installation.

The Next step is a review again, click Create environment, this can take a few minutes.

The Cloud9 environment comes with a pre-installed EC2 instance. You get Linux, the AWS-CLI, Git, Nodejs (6.11 via nvm, can be changed) , GCC and a whole bunch of other developer tools.

6. Installing and configuring BuckleScript

When the whole thing has started, you can run

npm i -g bs-platform
Enter fullscreen mode Exit fullscreen mode

right out of the box. Again, because of the OCaml compilation, this takes a few minutes.

After this, you can create a Reason project with

bsb -init my-first-service -theme basic-reason
Enter fullscreen mode Exit fullscreen mode

Now you need to change the bsconfig.json that was created in your new project folder, so the serverless framework later finds your output JS-files.

suffix: ".bs.js"
Enter fullscreen mode Exit fullscreen mode

to

suffix: ".js"
Enter fullscreen mode Exit fullscreen mode

You can run the compiler with npm run build. You should see a lib folder, with some temporary files and a src/demo.js file that is your successful build.

Interlude: Setting the EC2 instance back to t2.micro

After this, I suggest you go to the AWS Management Console, this time login with your AWS Root account user and switch back the t2.small instance to t2.micro.

Go to Services and EC2 in the Compute category.

Select Instances

Click right on your Cloud9 instance with Instance Type t2.small and set the Instance State to Stop.

Then Click right again on this instance and use the Instance Settings change Instance Type.

In this menu you can now choose t2.micro. This type will then be used if you restart the Cloud9 environment.

Sign out the root account user and sign back in as the new created user AWS Management Console and go back to your Cloud9 environment (Services -> Cloud9)

7. Installing and configuring Serverless

Now we need the serverless framework to test and deploy the functions we will write to AWS Lambda.

npm i -g serverless
Enter fullscreen mode Exit fullscreen mode

Then inside you my-first-service project folder you need to create a serverless project with a aws-nodejs template.

serverless create --template aws-nodejs --path my-first-service
Enter fullscreen mode Exit fullscreen mode

This will create another my-first-service folder inside your project folder.

You need to move the two files inside this new folder.

The handler.js has to move from my-first-folder/my-first-folder to my-first-folder/src

The serverless.yml has to move from my-first-folder/my-first-folder to my-first-folder

Change the serverless.yml to this

service: my-first-service

provider:
  name: aws
  runtime: nodejs6.10
  stage: dev
#  region: eu-west-1

functions:
  hello:
    handler: src/handler.hello
    events:
      - http:
          path: hello
          method: get
Enter fullscreen mode Exit fullscreen mode

I used region eu-west-1 this may be different for you, but this config is optional, it will use an US region on default.

As you can see, the first function hello is configured to run on an HTTP GET /hello event.

Serverless looks inside the src/handler.js to find an exported function hello.

To deploy the hello function created by serverless run

serverless deploy
Enter fullscreen mode Exit fullscreen mode

Cloud9 manages a pre-installed AWS-CLI for you, so the serverless framework can simply use your Cloud9 user to do its thing.

If everything went right, you will get a URL to the HTTP endpoint your AWS Lambda function is running.

To un-deploy your function again you can run

serverless remove
Enter fullscreen mode Exit fullscreen mode

Also, there is a way to "test" functions locally:

serverless invoke local --function <FUNCTION_NAME>
Enter fullscreen mode Exit fullscreen mode

8. Converting the JavaScript code to Reason

Now that we can deploy, we need to re-write our code in Reason.

For this, rename the

handler.js
Enter fullscreen mode Exit fullscreen mode

into

handler.re
Enter fullscreen mode Exit fullscreen mode

and replace its content with

type jsobject = {. "message": string};
[@bs.scope "JSON"] [@bs.val] external stringify : jsobject => string = "stringify";

let hello = (_event, _context, callback) => {
  let body = {
    "message" : "Hello from Reason!"
  };

  let response = {
    "statusCode": 200,
    "body": stringify(body)
  };

  [@bs] callback(Js.Nullable.null, response);
};
Enter fullscreen mode Exit fullscreen mode

What does this do?

First, it makes the global JSON.stringify method available in Reason. Everything in Reason has to be typed, so I create a simple jsobject type for a message object and then tell Reason, that the JSON.stringify method expects an input of that type.

Then I define my hello function, that will become my AWS Lambda function. I prepend the unused arguments with an underscore, since I'm only going to use the callback.

In the function I create an jsobject and put it into stringify. This becomse the "body" of a (HTTP) response object, that also needs a "statusCode".

Finally I call the callback function with a null for the error argument and my response. The [@bs] prevents the currying of the callback.

9. Compiling Reason to JavaScript

When we run

npm run build
Enter fullscreen mode Exit fullscreen mode

BuckleScript will create a src/handler.js that looks remarkably like the one we started with.

// Generated by BUCKLESCRIPT VERSION 2.1.0, PLEASE EDIT WITH CARE
'use strict';


function hello(_, _$1, callback) {
  var body = {
    message: "Hello from Reason!"
  };
  var response = {
    statusCode: 200,
    body: JSON.stringify(body)
  };
  return callback(null, response);
}

exports.hello = hello;
/* No side effect */
Enter fullscreen mode Exit fullscreen mode

Since a Reason file is a module and all Reason modules export their members by default, we don't need to explicitly export the function in the Reason code, but as we see, it will be exported non the less.

10. Deploying function to AWS Lambda

Now we can run the deployment again

serverless deploy
Enter fullscreen mode Exit fullscreen mode

and can navigate to the endpoint we get to call our function, this time written in Reason.

This should now print

{"message": "Hello from Reason!"}
Enter fullscreen mode Exit fullscreen mode




Conclusion

This is a very simple example of how to get these two bleeding edge technologies to work together.

Reason AND Serverless both keep their fingers to themselves and let us interface them purely with JavaScript files. Truly good team players.

The Reason JS-Interopt is a bit chatty, but at least you get a completely and soundly typed codebase out of this.

When you know the structure of lambda's event and context objects, you can use it to type your functions even more than I showed in this small example, which should decrease errors very much.

AWS Cloud9 is nice too, but since it is also rather new, it doesn't have all the plugins you're acustomed to by using Atom or VSCode. It's certainly cool that it comes preinstalled with many dev tools and even sets up the AWS-CLI, but at the moment I don't think it's a viable alternative to on-premise editors.

Thanks to Daniel Golant to check if I wrote crap :D

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .