[Today’s random Sourcerer profile: https://sourcerer.io/ciaraburkett]

The new “Function” platforms are to microservices what microservices are to the monolithic application architectures. They offer an even more fine-grained approach to modularizing applications. With automated scaling, it is promised our deployment headaches are a thing of the past. It’s an exciting idea, that developers simply write their code, and the platform takes care of keeping it running. Instead of hiring a DevOps team, all we have to do is write a check every month to the Function platform provider.

What some call “Serverless Computing” others call “Functions as a Service” (FaaS). Whatever you call it, the architecture depends on small constrained software modules deployed into a system that automatically scales to meet demand.

The word Serverless is an obvious misnomer because obviously servers are involved. What’s different is the developer does not get involved with deployment and scaling, which the hosting infrastructure provider takes care of.

Both microservice and serverless computing is a reaction to traditional monolithic application architecture. The idea is smaller modules are easier for a team to manage. The entire application results from connecting together all the modules via published well understood API’s. One potential gain is application reliability by all application modules respecting the published API of all other application modules, enforced by the module being in another service container.

Among the “Function” platforms, Amazon AWS Lambda, Microsoft Azure Functions, Google Cloud Functions, and IBM Cloud Functions, it is AWS Lambda is the furthest along.

In this article we’ll explore using AWS Lambda to develop a service using Node.js. Amazon recently announced an upgrade where developers using Lambda can now use an 8.10 runtime, which lets them use async functions. We’ll be sure to use async functions in the application.

Create an account with IAM, registering to use Lambda

The good news is AWS Lambda offers a free tier of service, meaning you won’t have to spend a dime to try this out.

Head to https://aws.amazon.com/ to sign up for an AWS account. Next head to https://console.aws.amazon.com/iam/ to create IAM user credentials.

In the left-hand pane, click on Users, then Add User

Enter a login name, and other settings for this user, when done click on Next: Permissions

We’re going to add this user to a Group, so click on Add User to Group and then Create Group

Enter a group name. Then using the filtering dropdown, filter the policies by Job Function and select Administrator Access. Click on Create Group.

The new group will be shown in a list of groups. Click on Next: Review

Look over the settings, and if you agree click on Create User

After that the IAM console will give you a URL like https://aws_account_number.signin.aws.amazon.com/console/ with which to sign in. Log out of the AWS console, then log-in using this new URL and user name and password you just setup.

Another important task in the IAM console is to set up access keys to the IAM user. Access keys are used for authentication, with the AWS Command-Line tool and other services. While viewing the summary page for an IAM user, click on the Security Credentials tab. On this page is a section labeled Access Keys and a button marked Create Access Key. Click on the button, and a pair of keys will be generated. You must record the keys in a safe place, and this is the only time AWS will ever in, the history of this or any other universe, show you those keys.

The AWS CLI tool stores configuration data in a couple hidden files in your home directory. The file ~/.aws/credentials is where you can store these keys, and the AWS CLI tool will use them to auto-authenticate with AWS services. See the documentation for more details: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html

AWS Lambda Hello World with Node.js

Let’s do a little tire kicking before we get to something serious. AWS Lambda provides a canned hello world application to try. To get to the Lambda dashboard, open up “All Services” and click on Lambda. Once on the dashboard click Create Function.

Fill in the form as shown here The Policy Templates dropdown has many choices, but leaving it blank is good enough for this phase. Click on Create Function.

You’re brought to the function editing page. There are several panes for editing different aspects of the function. The top pane configures Triggers, meaning which services can trigger this function. Leave that section blank for now.

Below that is the code editing pane for editing the function code. To start with we have this:

This is simple enough. We have an event handler, which is given an event object, which is an async function, meaning we can implement any asynchrocity we like so long as we end up with a return value. Because it is an async function, the return value turns into a Promise, and the AWS Lambda framework will already know how to deal with that Promise.

This is the essence of a Function, in a mathematical sense. In mathematics, a function is a magic box where you drop in data, and out pops a result. Here we have input, the event object, and output, the Promise resulting from executing the function.

Below that are panes for

Environment Variables, obviously meant for configuration settings

Tags, meant for organizing your Functions

Execution Roles, meant for permissions

Basic Settings, including maximum memory and execution time

Network, for network parameters

Debugging

Concurrency, meaning the maximum number of instances that will spawn

Let’s leave all this at their default settings for now.

To give this a whirl return to the top of the page and focus on the row of buttons at the top. The button marked Test is what we’ll be using. First we need to create a Test Event. In the dropdown next to the Test button select Configure test events. In the subsequent window click Create new test event and give an Event Name. Leave the supplied data as-is, and click the Create event.

An execution result appears after a moment:

This shows the expected text result, along with resource utilization data, and logging output. This becomes a little more interesting by changing the application to:

Click on Save, then Test, and the output now becomes:

The last thing to familiarize yourself with is the Monitoring tab.

Building a REST Service with AWS Lambda

That was fun, but our boss will want us to do some real work. A Lambda function can be triggered by any of a long list of event sources. For this example let’s tackle a REST service using Lambda. In this section we’ll make a service, using the AWS API Gateway, to invoke a simple Lambda function that handles GET, POST and DELETE requests.

Let’s start by creating a new Lambda function. It’s super-cheap and easy to create lots of functions. You only pay for the computation resources consumed by function execution, not for storing functions that are never used. This raises an enticing possibility — having multiple versions of the same function, and easily swapping between them simply by updating links.

Use the process in the previous section, give the function a name like myRESTservice. Then replace the generated code with this:

This has a fake “data store” that we’ll close our eyes and wish real hard it is a database. This handler function performs different actions based on the HTTP verb. REST services take actions corresponding to the HTTP request verb. These four are meant to correspond to the CRUD model, with POST equating to Create, GET equating to Read, PUT equating to Update, and DELETE equating to Destroy.

This Lambda function violates the principle that Lambda functions must be stateless. Since Lambda functions are automatically scaled to handle the traffic, there could be hundreds or thousands of myRESTservice containers each would have a different dataStore instance, and we’d receive different results. What we should do is store the data in a database, so that all myRESTservice instances act on the same data.

We need to setup an API Gateway instance first that handles those verbs. Go back to the AWS Console page, and search for and click on API Gateway. Then click on Create API, and enter a name like myRESTserviceAPI.

You’re then brought to a screen for editing the API. Use the editor to create these API methods:

For the /service selection, use the Actions dropdown to create a Resource. Then for DELETE, GET and POST, use the dropdown to create Methods. Do not create the OPTIONS Method, instead it is auto-created when we enable CORS support.

“Resource” is the word used in API Gateway to describe a given URL path, while “Method” is used in API Gateway to describe the HTTP verbs on a given Resource. Conceptually, each position in the URL structure is a Resource that is managed by HTTP-based Methods.

The next step is to configure each of the methods to connect with the Lambda function. Let’s start with the POST verb.

This graphically represents the processing of a request. The upper boxes represent two stages of processing the Request, which is passed to the Lambda function, and then there are two stages of Response processing. Click on Integration Request and you’ll see this:

Make sure to click on the Lambda Function choice, then set the Lambda Region to match the region where your function exists. For Lambda Function enter the name of the function. This connects a POST operation on the /service URL to invoke the named Lambda function.

The next step is to click on Body Mapping Templates and to configure how the POST request body is handled. Click on Add Mapping Template to add an application/json choice, like so:

As you do this a section will open below allowing you to generate a mapping template. Watch carefully for this, as the only indication may be that the browser scrollbar changes position. API Gateway allows for complex transformations of the incoming data, and you can organize the data payload any way you wish. The data payload will arrive in the Lambda as the event object. The mapping templates are written using the Velocity Templates language, and are documented in the AWS API Gateway developers guide at https://docs.aws.amazon.com/apigateway/latest/developerguide/mappings.html

In this case, select the Method Request Passthrough template. This template automatically passes through a bunch of useful data, and sets up the event object to match the code we wrote previously.

It can be useful to implement a custom mapping template to suit your needs.

Once you’ve done this, scroll back to the top of the window and click on Method Request and you will be returned to the overview of the POST request.

There’s a lot more we could configure here. For example instead of simply passing through the POST request data, we could set up a Model and validate the input against that Model.

Before we leave the POST operation, click on Actions and then choose Enable CORS. This enables cross-origin request support, and is what creates the OPTIONS method.

Finally, make the same changes to GET and DELETE operations that we did on the POST operation.

For now, click on the / path so the screen looks like this:

Then in the Actions dropdown, choose the Deploy action. You’ll be asked which Stage to deploy to, and you’ll need to create a stage. Enter “dev” as the stage name. In the future when redeploying the API, you’ll be able to make this choice:

Once you have done this, the API Gateway will bring you to the Stage Editor. It looks somewhat like the Resources editor we’ve used so far, but is about editing the characteristics of the deployed application.

There’s a lot we can do in the Stage editor. If you like, click around and explore what’s here but don’t change anything. There is one piece of information to pick up, and that’s the URL generated by the API Gateway for this service.

For the root of the service the URL will be something like:

And for the /service resource, the URL will be something like:

For now click on the Resources editor again. Open up the URL structure, and click on the POST operation. This time, click on the TEST icon, and you’ll see a screen looking like this:

Using this screen we can make a POST request that will pass through to the Lambda service. It’s a convenient way to test the service. Enter some JSON like:

And then click the Test button. If all goes well you will receive output like this:

This is the object returned from the Lambda function. Going by the mapping template, body-json, params, stage-variables and context are all generated by the request. Our code added the dataStore object. It will be instructive for you to compare this object with the mapping template.

Below this output is a detailed log of the body processing, passing data to the template, and processing the data returned by the Lambda function.

The next step of testing this is with a testing tool like Postman. Enter the URL we copied from the dev Stage Editor, then setup the request Body as shown here:

The returned object should be the same as before.

We created an API endpoint that handles three HTTP requests, GET, DELETE and POST. This is enough for most of the CRUD model (Create, Read, Update and Delete) that is the basis of so many API’s. Each of the HTTP verbs are connected to the same Lambda function.

This choice may be correct, since each method on the same resource may require sharing code between the methods. Or it may be incorrect since Lambda encourages us to implement small single-purpose functions. It’s up to your team as to which policy you will follow.

Making GET more GET-like (and DELETE, too)

One flaw with the code we just created is the GET and DELETE methods are incomplete. Both should accept an object ID to operate on. And while we’re critiquing the API, the POST operation shouldn’t be accepting any old object, but to accept/reject the request depending on the received object. We’ll get to the POST operation in a bit, but let’s first handle GET and DELETE.

With the GET method selected, click on Method Request. Then open up the URL Query String Parameters section and add this:

This supports adding a query string parameters that will be recognized by the API Gateway. Add as many as you like. For example you may want query string parameters to perform a search, and to return an array of objects, while supplying an ID parameter like this will return a single object.

Likewise you can open the HTTP Request Headers section to define HTTP headers that are to be recognized. We don’t need any custom HTTP headers in this API, but it’s nice to know you can do it if needed.

The same change should be made in the DELETE operation. Both GET and DELETE are expected by the REST model to operate on one or more objects.

Having done this, we can test as so:

Defining the query string caused the API Gateway to generate this input box in the Test UI.

Entering the answer to the ultimate question in that field, we get the following result:

As expected, the Lambda Function should access query string parameters using event.params.querystring.paramName. Of course this behavior is still dependent on the mapping template configured in the API. You’re quite free to implement a different mapping template to have a differently structured event object.

Validating data in the POST method

As we said earlier, the POST operation should check its input for validity. For example our Resource URL is /service, so POST should be given a Service object.

With API Gateway a Model defines the payload data structure. Models definitions are written using JSON Schema draft 4.

In the API Gateway, navigate to the Models tab and create a new model. Fill in the form as so:

This defines a model that accepts an object with properties name, categories, description, and price. The required array defines which of the properties are required in objects, and is used during validation.

We can now navigate back to the Test tab to test what we’ve done.

Enter a valid Service object as so:

And you’ll receive this result:

In event[“body-json”] is our Service object, and everything looks to be as expected. We must now check that the validation will fail.

With this invalid request body:

We get this error result:

Excellent, we have simple data validation of the POST request body. Even better, the execution log shows that the request was never passed over to the Lambda function.

Handling multiple URL Resources in a single Lambda function

As presented here each Resource would be handled by one Lambda function. In any case, it is possible for the Lambda function to implement further routing, so that a given Lambda handles multiple Resources.

You’ll notice in the object shown here that event.context[“resource-path”] has the URL path. One could easily use that data item to drive a router function that might be like this:

We aren’t going to implement this, just note it in passing if this is what you wish to do.

API Documentation using Swagger/OpenAPI

One advantage of the API Gateway service is it uses OpenAPI (a.k.a. Swagger) API definitions. The OpenAPI format for API documentation was originally called Swagger, and a couple years ago it transitioned to become an open standard supported by several companies and nurtured by the OpenAPI Initiative. The Swagger Tools are now just one of many toolchains for dealing with OpenAPI specifications. To learn more, see https://www.openapis.org/

The Swagger Tools themselves are documented at https://swagger.io/ These include online tools like the Swagger Editor, as well as code generation tools. From an OpenAPI spec we can not only deploy an API to the API Gateway, but we can generate a standalone implementation to run on our own server.

However, throughout the API Gateway UI it talks about importing and exporting Swagger v2 specifications. The OpenAPI Initiative released OpenAPI v3 in late 2017, so clearly API Gateway has yet to be updated to match.

All throughout the API Gateway user interface are little “Book” icons. If you click on that icon, an overlay dialog pops up letting you type in some documentation.

To generate a Swagger v2 specification, first deploy the application. Then go to the corresponding Stage Editor, and select the Export tab. You’ll see the following:

Hover the mouse over one of these, and you’ll see both JSON and YAML buttons appear. The YAML format is easier to read than the JSON format of the specification, so select that. Then compare the YAML with the API definitions we’ve constructed using the API Gateway UI.

If you head back to the API Gateway main page and click on Create API let’s direct your attention to the choices. You can create the API definition using a Swagger file, and import it directly into the API Gateway.

This is a first step to implementing your REST API as code that can be checked into a source code control system, like Git.

Conclusion

We’ve come a long way with this article, while only touching the surface of AWS Lambda functions and REST service implementation with API Gateway. We’ve been able to define a simple Lambda function, and then implement a few REST-like methods to interact with that function.

Amazon defined its Lambda function service to integrate with several other AWS services. For example functions can be triggered based on events in S3 buckets or DynamoDB databases. And, of course it’s possible by adding the required Node.js modules to use a huge variety of back-end services in a Lambda function.

What we’ve done with this article is to open a door to using hosted “Function as a Service” platforms.