Search This Blog

Sunday, 24 May 2020

REST + Dynamo = API Gateway

My use case is very straight forward - I have a table and I want to expose CRUD operations on the table - GET, ADD, DELETE, UPDATE.
My solution would be to expose a REST interface to this table. The GET translates to a table read, PUT to an insert, DELETE to a table delete and so on. AWS provides a feature called API Gateway which fits this use case. From AWS docs:
API Gateway creates RESTful APIs that:

* Are HTTP-based.
* Enable stateless client-server communication.
* Implement standard HTTP methods such as GET, POST, PUT, PATCH, and DELETE.
In this use case API Gateway(APIG) becomes the web interface for our table:
API Gateway handles all the tasks involved in accepting and processing up to 
hundreds of thousands of concurrent API calls. These tasks include traffic 
management, authorization and access control, monitoring, and API version 
management.
I am going to setup a simple Person table here with hash key as PersonId.
Now to setup a mechanism to access this record from HTTP - or a GET method for Person resource.
API Gateway link showed support for HTTP, REST and WEB SOCKET API. From the docs it appears that HTTP API is the new recommendation for APIG but it does not support all features supported by REST API yet. Also only REST API has support for non-Lambda integrations (e.g. Dynamo).
This sets up the API Gateway with GET method. As seen I had to add an IAM policy to allow API Gateway to talk with Dynamo Db:

Step 1: Create a Policy to give APIG access to Dynamo:

 Step2: Create a role and attach the policy to it:
The GET method looks as below:


This also shows how the Gateway works. A HTTP GET call is converted into a Dynamo Db POST (the Query API). Dynamo DB response is then converted to the Gateway HTTP Response.
Now to complete the setup of the GET method.
What is the mapping template ?
API Gateway uses mapping templates to transform incoming requests before they are 
sent to the integration back end. With API Gateway, you can define one mapping 
template for each possible content type. The content type selection is based on 
the Content-Type header of the incoming request. If no content type is specified 
in the request, API Gateway uses an application/json mapping template. By 
default, mapping templates are configured to simply pass through the request input.
Mapping templates use Apache Velocity to generate a request for your back end. API 
Gateway's reference documentation lists all of the properties and functions that 
API Gateway makes available in the templates.

The API Gateway is now ready. I tested my GET method
As seen I added the id to the url path and the resultant GET call retuned the Dynamo Record.
Execution log for request 1d3be14f-edbb-4460-9851-bd8fca8c77a4
Sat May 23 22:18:55 UTC 2020 : Starting 
execution for request: 1d3be14f-edbb-4460-9851-bd8fca8c77a4
Sat May 23 22:18:55 UTC 2020 : HTTP Method: GET, Resource Path: /persons/1
Sat May 23 22:18:55 UTC 2020 : Method request path: {id=1}
Sat May 23 22:18:55 UTC 2020 : Method request query string: {}
Sat May 23 22:18:55 UTC 2020 : Method request headers: {}
Sat May 23 22:18:55 UTC 2020 : Method request body before transformations: 
Sat May 23 22:18:55 UTC 2020 : Endpoint request URI: 
https://dynamodb.us-east-1.amazonaws.com/?Action=Query
Sat May 23 22:18:55 UTC 2020 : Endpoint request headers: {
Authorization=************142f25, X-Amz-Date=20200523T221855Z, 
x-amzn-apigateway-api-id=qbotcgknke, Accept=application/json, 
User-Agent=AmazonAPIGateway_qbotcgknke, 
X-Amz-Security-Token=cqJAK7rT/grZmyP[TRUNCATED]
Sat May 23 22:18:55 UTC 2020 : Endpoint request body after transformations: {
    "TableName": "Person",
    "PrimaryKey": "pId",
    "KeyConditionExpression": "pId = :v1",
    "ExpressionAttributeValues": {
        ":v1": {
            "S": "1"
        }
    }
}
Sat May 23 22:18:55 UTC 2020 : Sending request to 
https://dynamodb.us-east-1.amazonaws.com/?Action=Query
Sat May 23 22:18:55 UTC 2020 : Received response. Status: 200, Integration 
latency: 22 ms
Sat May 23 22:18:55 UTC 2020 : Endpoint response headers: {Server=Server, 
Date=Sat, 23 May 2020 22:18:55 GMT, Content-Type=application/x-amz-json-1.0, 
Content-Length=94, Connection=keep-alive, 
x-amzn-RequestId=A1OCMDLIK8DID4E08UFSKIJOJJVV4KQNSO5AEMVJF66Q9ASUAAJG, 
x-amz-crc32=492219340}
Sat May 23 22:18:55 UTC 2020 : Endpoint response body before transformations: 
{"Count":1,"Items":[{"pId":{"S":"1"},"name":{"S":"Robin"},"age":{"N":"20"}}],
"ScannedCount":1}
Sat May 23 22:18:55 UTC 2020 : Method response body after transformations: 
{"Count":1,"Items":[{"pId":{"S":"1"},"name":{"S":"Robin"},"age":{"N":"20"}}]
,"ScannedCount":1}
Sat May 23 22:18:55 UTC 2020 : Method response headers: {
X-Amzn-Trace-Id=Root=1-5ec9a14f-06c516d4e8c4c6627fdcbf16, 
Content-Type=application/json}
Sat May 23 22:18:55 UTC 2020 : Successfully completed execution
Sat May 23 22:18:55 UTC 2020 : Method completed with status: 200
We might not want to expose a Dynamo Db response to the client and therefore a suitable approach would be to implement a Integration Response that cleans up the dynamo db json to a clean Json

No comments:

Post a Comment