AWS unveiled API Gateway at its AWS Summit in New York City on 9 July of 2015. Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. Is API Gateway a RESTaaS (REST as a Service) ? Probably yes! because API Gateway with AWS Lambda and AWS DynamoDB permit to build a full REST Service. API Gateway is our HTTP/HTTPS gateway, in Lambda we have our business logic, without managing servers, and on Dynamo we have our data (no-sql data). I will try to describe the features and power of AWS API Gateway through the integration with Arduino devices, AWS Lambda and DynamoDB. Arduino collect some metrics from environment (temperature, pressure, position, etc) and send it to API Gateway by a HTTP call. API Gateway invoke a Lambda function that collect and transform info before to send to DynamoDB. All event will be tracked on Cloudwatch Logs. The metrics collected to DynamoDB will be then available for any Web Application able to interact with API Gateway via REST call. Demo with AWS API Gateway Lambda DynamoDB and Arduino
For people who know the AWS World know that Arduino may be used also with AWS Kinesis importing the SDK released by AWS. This experimental SDK permit to contact AWS Services on Arduino-compatible devices. I think that API Gateway permit to develop a more linear and simple code based on REST architecture without vendor lock-in. So i prefer to use this!
API Gateway and Lambda
In this section, we will see how to use API Gateway to create a custom API, connect your custom API to a set of AWS Lambda functions, and then call the Lambda functions from Arduino devices through API Gateway. The first step is to create our set of API. API is a collection of resources and methods that can be invoked through HTTP/HTTPS endpoints. In the API creation step we need to define only the name of API and a description, nothing else. After the API creation we see available only the resource root. The resource root, represented by a single forward slash character (/), is the programmatic URI location, known as a path, for accessing all of your API's resources. At this point we need to create the other resources and for every resource the methods to invoke it. For create a resource we need to specify only the Resource Name and Resource Path. On resource path we can add path parameters using brackets. For example, the resource path {address} represents a path parameter called 'address' where 'address' is a MAC address of the Arduino device and the resource /devices/{address}/metrics/ represent the collection of metrics of a specific device. After a creation of my API the dashboard of API Gateway present this configuration.
We have a set of resources and for every resource we need to specify one or more method for invoke it. Once you have chosen the method we must choose the integration type for it. The Integration type available are Lambda Function and HTTP Proxy. We will use a Lambda Function integration mode, so we will select "Lambda Function" from integration type specifyng region and ARN (Amazon Resource Name) of our lambda function.
Obviously before to point to Lambda function we must to create it! AWS Lambda is a compute service that runs your code in response to events and automatically manages the underlying compute resources for you. For now AWS Lambda supports code written in Node.js (JavaScript) and Java (Java 8 compatible). Our code can include existing libraries, even native ones. For this demo we chosed Java 8 Language. The code of this demo is available on my repository GIT github.com/PaoloL (please, the code is only for demo use). The package is build with Maven and it was loaded on Amazon S3. The configuration onf function is the following.
Configuration includes information such as "Runtime", we use Java 8, the "Handler" that will received the events, we will use a different method for every HTTP verb, the IAM role that AWS Lambda can assume for interacting with Dynamo and CloudWatch and finally the compute resource you want allocated and execution timeout. About handler i used this configuration:
- ApiGatewayGetDevice Lambda function use the it.paololatella.aws.demo.apigateway.LambdaToDynamo::getDevicesHandler Handler. This handler receive the request from GET /devices and list all devices resource
- ApiGatewayPostDevice Lambda function use the it.paololatella.aws.demo.apigateway.LambdaToDynamo::postDevicesHandler Handler. This handler receive the request from POST /devices and create a new device resource
- ApiGatewayGetDevicesAddress Lambda function use the it.paololatella.aws.demo.apigateway.LambdaToDynamo::getDevicesAddressHandler Handler. This handler receive the request from GET /devices/{address} request and return data about a specific device
- ApiGatewayPutDevicesAddress Lambda function use the it.paololatella.aws.demo.apigateway.LambdaToDynamo::putDevicesAddressHandler Handler. This handler receive the request from PUT /devices/{address} request and update data about a specific device
- ApiGatewayDeletDevicesAddress Lambda function use the it.paololatella.aws.demo.apigateway.LambdaToDynamo::deleteDevicesAddressHandler Handler. This handler receive the request from DELETE /devices/{address} request and delete data about a specific device
As you can see i used a single package for all Lambda functions. Infact the package it.paololatella.aws.demo.apigateway contain Devices class, Metrics class and LambdaToDynamo class. The first class implement a device (Arduino for example) object, the second class implement a metric object (position for example) and finally the LambdaToDynamo class is a main class with the handler specified above. So on Amazon S3 we have the full package, the same package for every lambda function, but the handler is different. I choose this configuration, instead of one where every lambda function has a different package, because in this mode we have only one package to maintaining and updating. Before you execute these Lambda functions, you must first create Lambda execution role in IAM. Without this role, Lambda cannot execute your code, cannot put logs on CloudWatch and cannot insert, delete or get item on DynamoDB.
For more information about execution roles in Lambda, see Permission Model in the AWS Lambda Developer Guide. In our case we have APIGatewayDemo roles with this IAM policy. In particular about Cloudwatch the
Serialization and DeSerialization
The Lambda function is invoked by API Gateway. Every method of our API is linked to an Handler of our Lambda Function. The handler is one of the methods defined on LambdaToDynamo Class. The first parameter of the method is the input to the handler which can be event data (published by an event source) or custom input you provide such as a string or any custom data object. AWS Lambda supports the following input/output types for a handler: simple Java types (String, Integer, Boolean, Map, and List types) or POJO (Plain Old Java Object) type or Stream type. The second parameter is the context. The context object allows you to access useful information available within the Lambda execution environment. For example, you can use the context parameter to determine the CloudWatch log stream associated with the function.
LambdaLogger logger = context.getLogger();
logger.log("JAVA_INFO: Received " + body.toString() + "\n");
About input in our case the input will be the body of our request and may be a String (better for Arduino devices) or JSON. In the first case the handler will receive a String object while in the second case the handler will receive a LinkedHashMap object. How you can see i don't explicit the object in input and use a dynamic implicit casting.
- public Map getDevicesAddressHandler(Object body, Context context)
- public Map putDevicesAddressHandler(Object body, Context context)
- public Map deleteDevicesAddressHandler(Object body, Context context)
- public ScanResult getDevicesHandler(Object body, Context context)
I can test the sample input of my Lambda Function with "Test" button and using "Configure sample event" action for pass a sample JSON to test.
About output the most important rule is that AWS Lambda serializes based on standard bean naming conventions. You should use mutable POJOs with public getters and setters. For example in this demo we can use the following Devices class and define an handler that return a POJO of devices for example public Devices getDevicesAddressHandler(Object body, Context context).
With this configuration AWS Lambda will perform a serialization of output returning a JSON output with this structure:
{
"address": "00:0a:95:9d:68:17",
"type" : "arduino",
"model" :"ethernet"
}
In my code i preferred to return a Map Object, but the return a Devices object would have been the same effect.
Input mapping
In API Gateway, we can use a mapping feature to transform some data from one format to another. You create and use input mapping templates and output mapping templates when you need to inform API Gateway about the schema of the data that is being sent to it from the caller or that it needs to output back to the caller, respectively. You can create models that enable API Gateway to make it easier for you to create mapping templates. More info about mapping template are available here. In our case we will use input mapping for mapping path parameters to a body request in JSON format. Don't forget that AWS Lambda expect JSON input and return JSON output! About input mapping we need to make a input mapping model on API Gateway and use this for mapping, for example, the device address parameters on body.
In the above screenshot we can see how we map the address of the device, passed by a path parameter on PUT /devices/{address}, in the request body. We map address by this mapping model.
#set($inputRoot = $input.path('$'))
{
"address" : "$input.params('address')",
"model" : "$inputRoot.model",
"type" : "$inputRoot.type"
}
With this model we have "address" key on value returned by $input.params('address') therefore on address passed by path parameters. Instead "model" key and "type" key will be mapped by $inputRoot.model and $inputRoot.type therefore on model and type passed on body request. The $input.params('address') retrieve the address of device from url and map it to correspondent key present on body request. Great right ?? Now we can test mapping model directly on AWS API Gateway console.
The address of device passed on URI is now mapped in body request and send it to AWS Lambda. While a test is possible to see the logs of API Gateway with the body before and after the input mapping.
DynamoDB
DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. With AWS Lambda we can write code for retrieve, insert, update or delete an item to DynamoDB. In our case the DynamoDB table is structured as follows: an item is a description of your device where the attributes are address, model and type. Every Lambda Handler invoke a method of LambdaToDynamo Class which is responsible to insert, delete, update or retrieve a item or more items.
The code about DynamoDB and Lambda integration is available on my repository GIT.
Test and Deploy
To test a method for an API in API Gateway, you can use the API Gateway console. In the Resources pane, choose the method that you want to test and choose TEST. After a test the following information will display: body request, http status code, latency time between the request from the caller and returned response, body response and simulation of logs
Now we can deploy our API and test it. In the box that contains the name of the API that we want to deploy, choose Resources and choose Deploy API. In the Deployment stage, insert the name of the stage that you want to use for the deployment. For example a stage with name "v1" will make public our API on URL: https://xyz123.execute-api.eu-west-1.amazonaws.com/v1
To enable a cache for the API, on the Settings tab, in the Cache Settingsarea, check Enable API cache. Then, for Cache capacity, choose a cache size. To generate code to call the API from Android, iOS, or JavaScript, you use the SDK Generation tab. For more information, see Generate an SDK for an API.
To enable Amazon CloudWatch Logs for all of the methods that are associated with this API in API Gateway on the Settings tab, in the CloudWatch Settings area, check Enable CloudWatch Logs. The Logs will be available on CloudWatch service.

Finally we can test the API with Postman and see the output.













