API Management / Monitoring / Serverless / Sponsored / Contributed

Build a Serverless API with AWS Gateway and Lambda

1 Sep 2020 3:00pm, by

Thundra sponsored this post.

APIs are a crucial part of any web application and there are different techniques for development and design. Serverless is one approach gaining popularity, because of its cost-efficiency, scalability and relative simplicity. As a leading serverless provider, Amazon Web Services (AWS) has made a huge contribution to the world of serverless development, and in this article, we will explain general API implementation concepts using AWS Lambda and other AWS services.

Why AWS Lambda?

Serkan Özal
Serkan is co-founder and CTO of Thundra. He has 10+ years of expertise in software development, is an AWS Certified PRO and has a patent on distributed environments. He mainly works on serverless architectures, distributed systems and monitoring tools.

AWS Lambda is an AWS service that is responsible for running particular functions in response to particular triggers — events happening in the application. Those triggers could be HTTP calls; events from other AWS services like S3, Kinesis, or SNS; or just recurrent scheduled events. Functions are executed in some type of ephemeral containers, which are fully provisioned and scaled by AWS, so the development team can focus more on the code and functionality than on infrastructure.

Another attractive feature is the pay-as-you-go payment model, where you are charged only for the total execution time of your functions and do not pay for idle time. Of course, like any other service, Lambda has limits and is sometimes not suitable for certain tasks — such as very long-running jobs, heavy computing jobs, or processes that require control over the execution environment. However, AWS Lambda usually works perfectly for implementing APIs.

The Role of API Gateway

AWS API Gateway is a service allowing developers to create and manage HTTP endpoints, map them to particular AWS resources, and configure custom domains, authorizing mechanisms, caching and other features. API Gateway is the fundamental part of serverless API, because it is responsible for the connection between a defined API and the function handling requests to that API.

HTTP APIs

As mentioned, API Gateway includes a lot of functionality and integrations. At some point, though, Amazon realized that serverless developers usually do not require all of those features, but instead need a general simplification of the implementation process. That is probably why in late 2019, AWS announced the new HTTP APIs, a lite version of API Gateway, which dramatically simplifies the developer experience and provides better performance and lower costs for serverless APIs. Although it is simple, HTTP APIs still support such important features as configuring CORS for all endpoints, JWT integration, custom domains and VPC connections.

Understanding Serverless API Concepts

In order to easily understand the main concepts of serverless API implementation, we’ll build a very minimalistic example of a simple “virtual whiteboard” application, consisting of two simple endpoints: POST for writing messages on a whiteboard, and GET for fetching the three most recent messages. We will also consider other possible features — like path parameters, CORS, and authorizers — but we’ll keep the final implementation simple and clear to read.

AWS DynamoDB

We will make our project completely serverless, by using AWS DynamoDB for storing messages. This database corresponds to serverless principles, is easy to use, and offers a pay-per-request model that is really cost-effective. DynamoDB is a NoSQL key-value database offered by AWS, where your data is stored across AWS servers and fully managed by Amazon.

AWS Serverless Application Model

In order to continue further implementation, you’ll need an AWS account and AWS Serverless Application Model (SAM) installed and configured. SAM is a tool for creating, updating, and managing serverless applications and all the resources needed for the application to operate. With AWS SAM, you don’t need to create every single service manually via web console, but just to describe all the things needed in the special template file.

After you’ve installed the CLI, navigate to the directory you are going to work in and run this command:

Initializing new project

Select the first option, then select “Quick Start from Scratch.” This will create a “whiteboard” directory with a minimum of setup files inside.

Define the Required Resources Needed

First, open the template.yml file and remove everything below the “Resources” section. Before moving to the API itself, let’s create the secondary resources. Define a DynamoDB table where messages will be stored:

Declaring DynamoDB table

The code above will tell AWS to create a DynamoDB table, where attribute “partKey” will be a partition key that is the same for all records and “createdAt” will be a range key, allowing further sorting by timestamp. We may also add other keys and values into the records, but you are not required to define those.

Now, in the same file, just below the previous definition, declare the HTTP API to which all future endpoints and functions will be related.

Declaring HTTP API

The definition is very small and simple since we just included the stage name and CORS configuration, which are not actually required either. This illustrates how simple and clean API creation can be. However, there are many possible properties to add, such as a reference to authorization function, definition of the domain to use, logging settings, and others.

Define API Handlers Functions

Finally, when we have the API defined, let’s also declare two functions connected to its particular endpoints.

Declaring handlers for POST and GET requests

The above code is quite self-descriptive: two functions, one of which will be invoked upon a POST request to the “/messages” path, and the other of which will be invoked upon a GET request to the same path. Both functions have a capacity of 128 MB RAM and a five-second timeout. The functions’ code is found in the postMessage.js and getMessage.js files under the /src/handlers/ directory. We are going to create those right now. (Note that we’ve provided full access to the DynamoDB in the “Policies” section of each function, just to make things easier.) In a real project, you should consider providing more granular access.

Coding the Functions

Navigate to the /src/handlers directory and create files there with the following content:

postMessage.js

POST request handler’s code

This function will run in response to POST requests and will parse the author and text of the message from the request body and save that data into the database. It also fills the “partKey” attribute with the same value for all records. Although usually this is not a good practice, it is completely fine for this example, as it allows you to sort by range key among all items with the same partition key. Note that DynamoDB always expects string data to be saved, even if the type of attribute is a number.

getMessages.js

GET request handler’s code

In this function we first get records with “partKey” equal to “board,” then use “ScanIndexForward” set to “false” to sort messages so that the most recent is first, and finally we use the “Limit” property to limit results to three messages.

Deployment

Deployment with AWS SAM is easy and can be done with a single command and a few inputs. Navigate to the root directory of the project and run the following command:

Deployment command

You will then be asked to enter the name of your app and the AWS region to use. You’ll also need to confirm some actions:

Fill in and accept settings

After you’ve completed all the confirmations, deployment will start, and you’ll see all the resources being created. This takes about a minute or less.

List of resources to be created and their statuses

When the process is finished, open the AWS web console in your browser, navigate to API Gateway service, find the newly created API, and copy the URL to the root endpoint of your API.

URL to API root endpoint

Testing the API

Let’s create a few messages on the board using the default “curl” tool. Use the following command, but replace placeholders with your own data.

Performing POST request with curl

Send a few different requests with different messages. If everything is OK, you’ll see “Message posted on board!” in the console without any errors.

In order to fetch the last messages, run an even shorter command:

Performing GET request with curl

Congratulations! You’ve just built a simple HTTP API with AWS Lambda and AWS SAM. Of course, in a real project you would use additional features and configurations, but the principles remain the same: define resources, define configurations, write the code, and run deploy.

Connect Thundra Monitoring

It’s very good practice to have monitoring set up — especially for serverless applications, as they are really tricky to debug and trace.

Connect Thundra monitoring to the newly created Lambda functions (see the quick start guide). Once you’ve connected Thundra, you’ll need to instrument the “postMessage” and “getMessages” Lambda functions in order to see detailed information about every single invocation and have a global picture of your application.

Select functions in the list and click the “Instrument” button, then confirm instrumenting by clicking “OK.”

Confirm Lambda function instrumenting

Try to make a few other requests to your API, then return to the Thundra dashboard, click on the function’s name, and select any of the invocations in the invocations list. You’ll see details about timing, performance, function inputs and outputs, etc. This can be extremely useful in debugging APIs in real-life projects.

Details about a single invocation

If you or your company use serverless in complex projects with different AWS or third-party services integrated, you should definitely consider using the unique tracing feature, which will dramatically simplify application troubleshooting and debugging.

Are HTTP APIs Worth Using?

HTTP APIs plus AWS Lambda is a great way to build performant and cost-effective APIs. Although it is actually a lite version of API Gateway REST APIs, it still provides all the needed functionality and covers 90% of developers’ needs. HTTP APIs don’t support some useful features, like caching, schema validation and response transformations. Caching, though, is probably not something you’ll need, as HTTP APIs are much faster then the old REST APIs, and validation and transformations can be done at the function’s code level.

If your development team has no other reason to refuse to use HTTP APIs, you may confidently proceed to development with this great feature. Usually, the journey of a serverless transaction starts with an API call and it can be daunting to trace an asynchronous flow of events. Thundra comes to the rescue for such issues, with its end-to-end distributed tracing feature. Thundra is free up to 250K requests per month, which can be quite useful for small projects or startups.

If you’d like to gain full observability through serverless APIs, sign up for Thundra today

Amazon Web Services is a sponsor of The New Stack.

Feature image via Pixabay.

At this time, The New Stack does not allow comments directly on this website. We invite all readers who wish to discuss a story to visit us on Twitter or Facebook. We also welcome your news tips and feedback via email: feedback@thenewstack.io.

A newsletter digest of the week’s most important stories & analyses.