Quantcast
Channel: Babbel Bytes
Viewing all articles
Browse latest Browse all 115

AWS Lambda and APIGateway as an AJAX-compatible API-endpoint with custom routing

$
0
0

AWS Lambda is a powerful tool to build serverless applications, especially when backed by APIGateway and Swagger. Lambda executes your code without the need for you to manage a dedicated server. APIGateway provides a front-end for your Lambda to be easily accessed from the Internet via endpoints that can be configured with the Swagger framework. In this article we’ll take a look at one specific example of an AJAX endpoint that uses custom path parameters, something typically problematic to implement because of Swagger limitations.


10000 Gates in Kyoto

Task

Build an HTTP proxy endpoint reachable from a browser using an AJAX-call with an address like path/to/endpoint/{route+}, where route is a URL path (this means that it can contain forward slashes - e.g. path/to/endpoint/foo/bar).

Framework

AWS Lambda - provides the backend for the endpoint. It contains code with business logic, processes user input, and returns a JSON response.

Amazon APIGateway - provides the connection layer to the Lambda from the Internet over HTTP, because you can’t call Lambda functions directly without AWS credentials.

Swagger - describes the APIGateway resource configuration.

Plan

Let’s assume that you have a Lambda function already. If not, then create a new one with the following code:

exports.handler=(request,_context,callback)=>{constbody={url:'prefix/'+request.pathParameters.route};constresponse={statusCode:200,body:JSON.stringify(body)};callback(null,response);});

This function takes a request and returns a JSON with the modified URL. In this case, the function just attaches prefix to the requested path. This is good enough for the shown example but in production you would likely have something more meaningful such as traffic-splitting, domain-switching, or other routing functionality.

In order to connect the Lambda to the Internet, we need to define a Swagger configuration for the APIGateway. You should note that the route parameter can contain any string as is the case when you build a request proxy and your route parameter contains the requested URL. Unfortunately, doing this with a basic Swagger configuration is not possible because the parameters cannot contain forward slashes. In APIGateway this would only be possible with a special extension for Swagger called x-amazon-apigateway-any-method. But herein lies the problem…

Problem

The ANY method will pass all requests to the Lambda function. It’s a good-enough solution if you call an endpoint only from a backend or mobile app but if you call it from a browser, the browser will fire a pre-flight request with the OPTIONS method. The response should contain an empty body and CORS headers which would allow us to perform the AJAX request. In this case however, the request will end up in the Lambda function and the main code will be executed, returning JSON as a result and no CORS. The browser will then reject it and throw an error.

You can hack-fix it on the side of the Lambda function by checking the request method and returning a mock for OPTIONS, but in that case, why use tools as powerful as APIGateway and Swagger in the first place?

Solution

Actually, all you need to do is to define x-amazon-apigateway-any-method with default behaviour and override the necessary methods with an actual configuration.

Here is an example:

swagger:'2.0'info:title:HTTP-proxy APIdescription:Example HTTP-proxy APIversion:'1.0.0'schemes:-httpsproduces:-application/jsonpaths:/path/to/endpoint/{route+}:x-amazon-apigateway-any-method:produces:-application/jsonconsumes:-application/jsonx-amazon-apigateway-integration:type:mockpassthroughBehavior:when_no_templatesresponses:default:statusCode:"403"responseParameters:method.response.header.Access-Control-Allow-Origin:"'*'"responseTemplates:application/json:__passthrough__requestTemplates:application/json:"{\"statusCode\":403}"responses:403:headers:Access-Control-Allow-Origin:type:stringdescription:403 responseget:produces:-application/jsonconsumes:-application/jsonsummary:This is a test Lamda HTTP-endpointparameters:&parameters-name:routein:pathtype:stringrequired:truex-amazon-apigateway-integration:type:aws_proxyhttpMethod:POSTuri:%HERE_GOES_YOUR_LAMBDA_ARN%credentials:%HERE_GOES_YOUR_LAMBDA_INVOCATION_ROLE%responses:200:headers:Access-Control-Allow-Origin:type:stringdescription:Returns the experiment configuration and the destination for a specific targetoptions:produces:-application/jsonconsumes:-application/jsonsummary:OPTIONS method defined for AJAX-callsparameters:-name:routein:pathtype:stringrequired:trueresponses:200:description:200 responseheaders:Access-Control-Allow-Origin:type:stringAccess-Control-Allow-Methods:type:stringAccess-Control-Allow-Headers:type:stringx-amazon-apigateway-integration:passthroughBehavior:when_no_templatesresponses:default:statusCode:"200"responseParameters:method.response.header.Access-Control-Allow-Methods:"'GET,POST,PUT,PATCH,DELETE,OPTIONS'"method.response.header.Access-Control-Allow-Headers:"'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"method.response.header.Access-Control-Allow-Origin:"'*'"responseTemplates:application/json:__passthrough__requestTemplates:application/json:"{\"statusCode\":200}"type:mock

Here we define a x-amazon-apigateway-any-method block that returns a 403 status code by default. After, we define a GET method, overriding the default behaviour with a call to the Lambda function. Finally, we define an OPTIONS method that returns Access-Control-Allow-* headers, necessary for AJAX calls. All we need to do now is to return the Access-Control-Allow-Origin header together with the Lambda response. Let’s modify our code:

exports.handler=(request,_context,callback)=>{constbody={url:prefix/+request.pathParameters.route};constresponse={statusCode:200,headers:{'Access-Control-Allow-Origin':'*'},body:JSON.stringify(body)};callback(null,response);});

Now our problem is fixed. We’ve defined an AJAX-compatible API endpoint using APIGateway tooling and can call our Lambda function from the Internet.

Photo by Jeremy Goldberg on Unsplash


Viewing all articles
Browse latest Browse all 115

Trending Articles