Looking for the best method to locally testing your serverless architecture using AWS Lambda + AWS API Gateway? At Doorr, we challenged ourselves to exactly this task as we had been searching for the ideal solution that made local testing seamless, easy, and quick to setup.
We identified a number of solutions, but if felt that they were all either expensive, heavy, or required a lot of boilerplate code. None of them were suitable for us — and likely wouldn’t be suitable for any project with a large existing codebase that has a lot of routes built-in.
Then we stumbled upon it. A package that allowed us to map AWS API Gateway routes to an express server without a large overhead, which in return, set up the local testing environment that we needed!
Here’s how we achieved it:
What we need
· Node.js And Typescript — Using versions 10.16 and 3.8 respectively, but versions higher would work.
· Express.js — To set up the server
· AWS Node SDK — To pull AWS API Gateway APIs
· Swagger Routes Express — To map all our routes to Express
· Open API types (preferred) — Type information for OpenApi compliant documents.
After installing all the packages, and reading a bit about them, you may have inferred where we’re heading. If not, we’ll guide you through it.
First of all, the Swagger Routes package needs an Open API compliant document to map all of the routes to an Express server. It’s up to you to choose which version you’re more comfortable with, V2 or V3, but regardless of the version, we need to pull the document and place it in our codebase to get the server started.
Setting up the server
Here is where the actual fun begins: we create a makeApp function that returns an Express application which later can be used as app.listen(...).
Here you’ll see we have in a separate file two constants that define all the names of our AWS API Gateway APIs (We have many in our project) and another defining the API Key (you can pull this value from the AWS Console).
For each of the AWS API Gateway APIs, we pull the .json file as a buffer and use the connect function from the Swagger package to append the routes to the app.
At this point, you might be wondering what’s the setOperationIds call for. So, it depends on your AWS handler setup. In our case, we have a general handler for each API — Imagine we have a user API, so we have userApiLambdaHandler that gets all the request information and then calls the right lambda function based on the request.
This function adds an operationId for every route handler that we have in our OpenAPI document. That way, the Swagger Package knows which function to call for each route defined. This code also handles the AWS API Gateway any method, so it creates a GET, POST, PUT and DELETE operations in the document if it’s present.
AWS Lambda Handler to Express Handler
For all the above to work, we need a way to map the request and response payloads from Express to our Lambda Handlers. Here’s how:
The mapExpressRequestToLambdaRequest function does the job. We just need to call it in our expressHandler, and then we send a response back when the done callback is called.
And that’s it! You just need to set the operationId in all of your route operations defined in the AWS API Gateway export to this handler and your server is good to go.
There are many ways we could test our lambda functions locally, even manually running our scripts and functions, but having a local server speeds up the development by 10x because we get all of the features and benefits of any REST Client in a serverless architecture.
The wonderful and marvelous Swagger package does the job really well. Kudos to Dave, the creator of the package, for sharing it with everybody. We just need a way to add the operationId in our Swagger doc and a function that maps the different payloads from Express to AWS API Gateway.
If you already maintain your Open API document, you don’t even need to get the export from AWS API Gateway and you can use it locally, whether it’s in a YAML or JSON format, you just need to parse it and send it out to the Swagger package.