API Gateway
Persistence:
11 minute read
Introduction
API Gateway is a managed service that enables developers to create, deploy, and manage APIs (Application Programming Interfaces).
It allows easy creation of REST, HTTP, and WebSocket APIs to securely access data, business logic, or functionality from backend services like AWS Lambda functions or EC2 instances.
API Gateway supports standard HTTP methods such as GET
, POST
, PUT
, PATCH
, and DELETE
and integrates with various AWS services, including Lambda, Cognito, CloudWatch, and X-Ray.
LocalStack supports API Gateway V1 in the Community image and API Gateway V2 in the Pro image. LocalStack allows you to use the API Gateway APIs to create, deploy, and manage APIs on your local machine to invoke those exposed API endpoints.
The supported APIs are available on the API coverage page for API Gateway V1 & API Gateway V2, which provides information on the extent of API Gateway’s integration with LocalStack.
Getting started
This guide is designed for users new to API Gateway and assumes basic knowledge of the AWS CLI and our awslocal
wrapper script.
Start your LocalStack container using your preferred method.
We will use the Lambda proxy integration to integrate an API method with a Lambda function.
The Lambda function will be invoked with a GET
request and return a response with a status code of 200
and a body containing the string Hello from Lambda!
.
Create a Lambda function
Create a new file named lambda.js
with the following contents:
'use strict'
const apiHandler = (payload, context, callback) => {
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: 'Hello from Lambda'
}),
});
}
module.exports = {
apiHandler,
}
The above code defines a function named apiHandler
that returns a response with a status code of 200
and a body containing the string Hello from Lambda
.
Zip the file and upload it to LocalStack using the awslocal
CLI.
Run the following command:
$ zip function.zip lambda.js
$ awslocal lambda create-function \
--function-name apigw-lambda \
--runtime nodejs16.x \
--handler lambda.apiHandler \
--memory-size 128 \
--zip-file fileb://function.zip \
--role arn:aws:iam::111111111111:role/apigw
This creates a new Lambda function named apigw-lambda
with the code you specified.
Create a REST API
We will use the API Gateway’s CreateRestApi
API to create a new REST API.
Here’s an example command:
$ awslocal apigateway create-rest-api --name 'API Gateway Lambda integration'
This creates a new REST API named API Gateway Lambda integration
.
The above command returns the following response:
{
"id": "cor3o5oeci",
"name": "API Gateway Lambda integration",
"createdDate": "2023-04-27T16:08:46+05:30",
"apiKeySource": "HEADER",
"endpointConfiguration": {
"types": [
"EDGE"
]
},
"disableExecuteApiEndpoint": false
}
Note the REST API ID returned in the response. You’ll need this ID for the next step.
Fetch the Resources
Use the REST API ID generated in the previous step to fetch the resources for the API, using the GetResources
API:
$ awslocal apigateway get-resources --rest-api-id <REST_API_ID>
The above command returns the following response:
{
"items": [
{
"id": "u53af9hm83",
"path": "/"
}
]
}
Note the ID of the root resource returned in the response. You’ll need this ID for the next step.
Create a resource
Create a new resource for the API using the CreateResource
API.
Use the ID of the resource returned in the previous step as the parent ID:
$ awslocal apigateway create-resource \
--rest-api-id <REST_API_ID> \
--parent-id <PARENT_ID> \
--path-part "{somethingId}"
The above command returns the following response:
{
"id": "zzcvcf56ar",
"parentId": "u53af9hm83",
"pathPart": "{somethingId}",
"path": "/{somethingId}"
}
Note the ID of the root resource returned in the response. You’ll need this Resource ID for the next step.
Add a method and integration
Add a GET
method to the resource using the PutMethod
API.
Use the ID of the resource returned in the previous step as the Resource ID:
awslocal apigateway put-method \
--rest-api-id <REST_API_ID> \
--resource-id <RESOURCE_ID> \
--http-method GET \
--request-parameters "method.request.path.somethingId=true" \
--authorization-type "NONE"
The above command returns the following response:
{
"httpMethod": "GET",
"authorizationType": "NONE",
"apiKeyRequired": false,
"requestParameters": {
"method.request.path.somethingId": true
}
}
Now, create a new integration for the method using the PutIntegration
API.
$ awslocal apigateway put-integration \
--rest-api-id <REST_API_ID> \
--resource-id <RESOURCE_ID> \
--http-method GET \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:apigw-lambda/invocations \
--passthrough-behavior WHEN_NO_MATCH
The above command integrates the GET
method with the Lambda function created in the first step.
We can now proceed with the deployment before invoking the API.
Create a deployment
Create a new deployment for the API using the CreateDeployment
API:
$ awslocal apigateway create-deployment \
--rest-api-id <REST_API_ID> \
--stage-name test
Your API is now ready to be invoked. You can use curl or any HTTP REST client to invoke the API endpoint:
$ curl -X GET http://localhost:4566/restapis/<REST_API_ID>/test/_user_request_/test
{"message":"Hello World"}
New API Gateway implementation
Note
Since 3.8.0, LocalStack supports a new API Gateway implementation for both API Gateway v1 (REST API) and v2 (HTTP API).
You can set the following flag PROVIDER_OVERRIDE_APIGATEWAY=next_gen
to use the new implementation.
We’re entirely reworked how REST and HTTP APIs are invoked, to closely match the behavior on AWS. This new implementation has improved parity on several key areas:
- for REST APIs:
- properly applying the request and response data mappings for all integrations
- better parity for VTL template rendering (Mapping Templates) for the integrations supporting it (
AWS
,HTTP
andMOCK
) - properly supporting Mapping Templates overrides
- better parity for
AWS_PROXY
integration payloads - out of the box support for most of
AWS
integrations - support for Gateway Responses
- we currently only support overriding the Status Code and returning the proper exception, and do not apply mapping template (response body) or parameter mappings (response headers)
- for HTTP APIs:
- better validation and parity for most API operations related to HTTP APIs
- better parity and properly applying request and response Parameter Mappings for all integrations
- we’ve properly implemented the
AWS_PROXY
Lambda integration andREQUEST
Lambda Authorizer payloads to be fully on parity with AWS - better routing handling
- better CORS handling, especially around automatic
OPTIONS
responses - support for automatic deployments of your stages
- For both REST and HTTP APIs:
- support Stage and Deployments, meaning you can now have different stages pointing to different deployments like in AWS
- better logging on the different steps in the LocalStack logs
Currently, WebSockets APIs are still using the default implementation.
As we’re closely following AWS, for REST and HTTP APIs, you now need to create a deployment in order for your API to be reachable.
Thanks to this improvement, you can now create different stages point to different deployments of your API (for example, dev
and production
) with different settings and stage variables, and those will be reflected in LocalStack.
LocalStack features
LocalStack provides additional features and functionality on top of the official AWS APIs, to help you develop, debug, and test your local API Gateway APIs.
Accessing HTTP APIs via Local Domain Name
To demonstrate how to access APIs through LocalStack’s local domain name, consider the following Serverless configuration that shows two Lambda functions (serviceV1
and serviceV2
) that are connected to an API Gateway v1 (http
event) and an API Gateway v2 endpoint (httpApi
event), respectively:
...
plugins:
- serverless-localstack
custom:
localstack:
stages: [local]
functions:
serviceV1:
handler: handler.handler
events:
- http: # for API GW v1 integration
method: POST
path: /my/path1
serviceV2:
handler: handler.handler
events:
- httpApi: # for API GW v2 integration
method: POST
path: /my/path2
After you deploy the Lambda functions and API Gateway endpoints, you can access them using the LocalStack edge port (4566
by default).
There are two alternative URL formats to access these endpoints.
Recommended URL format
The recommended URL format for accessing APIs is to use the following URL syntax with an execute-api
hostname:
http://<apiId>.execute-api.localhost.localstack.cloud:4566/<stageId>/<path>
Here’s an example of how you would access the HTTP/REST API with an ID of 0v1p6q6
:
http://0v1p6q6.execute-api.localhost.localstack.cloud:4566/local/my/path2
Note that the local stage ID is added in this example.
Adding the stage ID is required for API Gateway V1 APIs, but optional for API Gateway V2 APIs (in case a $default
stage is created).
For v2 APIs, the following URL should also work:
http://0v1p6q6.execute-api.localhost.localstack.cloud:4566/my/path1
Alternative URL format
Note
If you are using the new API Gateway implementation, the _user_request_
format is deprecated, and you should use the following:
http://localhost:4566/_aws/execute-api/<apiId>/<stageId>/<path>
This new endpoint more closely resembles the recommended URL format, and allows you to use HTTP APIs with a $default
stage.
The alternative URL format is an endpoint with the predefined path marker _user_request_
:
http://localhost:4566/restapis/<apiId>/<stageId>/_user_request_/<path>
For the example above, the URL would be:
http://localhost:4566/restapis/0v1p6q6/local/_user_request_/my/path1
This format is sometimes used in case of local DNS issues.
WebSocket APIs (Pro)
WebSocket APIs provide real-time communication channels between a client and a server. To use WebSockets in LocalStack, you can define a WebSocket route in your Serverless configuration:
...
plugins:
- serverless-localstack
functions:
actionHandler:
handler: handler.handler
events:
- websocket:
route: test-action
Upon deployment of the Serverless project, LocalStack creates a new API Gateway V2 endpoint.
To retrieve the list of APIs and verify the WebSocket endpoint, you can use the awslocal
CLI:
$ awslocal apigatewayv2 get-apis
{
"Items": [{
"ApiEndpoint": "ws://localhost:4510",
"ApiId": "129ca37e",
...
}]
}
In the above example, the WebSocket endpoint is ws://localhost:4510
.
Assuming your Serverless project contains a simple Lambda handler.js
like this:
module.exports.handler = function(event, context, callback) {
callback(null, event);
};
You can send a message to the WebSocket at ws://localhost:4510
and the same message will be returned as a response on the same WebSocket.
To push data from a backend service to the WebSocket connection, you can use the Amazon API Gateway Management API.
In LocalStack, use the following CLI command (replace <connectionId>
with your WebSocket connection ID):
$ awslocal apigatewaymanagementapi \
post-to-connection \
--connection-id '<connectionId>' \
--data '{"msg": "Hi"}'
Custom IDs for API Gateway resources via tags
You can assign custom IDs to API Gateway REST and HTTP APIs using the _custom_id_
tag during resource creation.
This can be useful to ensure a static endpoint URL for your API, simplifying testing and integration with other services.
To assign a custom ID to an API Gateway REST API, use the create-rest-api
command with the tags={"_custom_id_":"myid123"}
parameter.
The following example assigns the custom ID "myid123"
to the API:
$ awslocal apigateway create-rest-api --name my-api --tags '{"_custom_id_":"myid123"}'
{
"id": "myid123",
....
}
You can also configure the protocol type, the possible values being HTTP
and WEBSOCKET
:
$ awslocal apigatewayv2 create-api \
--name=my-api \
--protocol-type=HTTP --tags="_custom_id_=my-api"
{
"ApiEndpoint": "my-api.execute-api.localhost.localstack.cloud:4566",
"ApiId": "my-api",
"Name": "my-api",
"ProtocolType": "HTTP",
"Tags": {
"_custom_id_": "my-api"
}
}
Note
Setting the API Gateway ID via_custom_id_
works only on the creation of the resource, but not on update in LocalStack.
Ensure that you set the _custom_id_
tag on creation of the resource.Custom Domain Names with API Gateway (Pro)
You can use custom domain names with API Gateway REST APIs and HTTP APIs.
To use custom domains, you will need to set up an API Gateway Domain Name and create an API Mapping linked to your API.
Assuming your custom domain is set up as test.example.com
to point to your REST API with a base path mapping base-path
linked to your stage named dev
, the following command will be directed to your REST API on the dev
stage.
You should include the Host
header with the custom domain name in your request, so you don’t need to set up any custom DNS to resolve to LocalStack.
$ curl -H 'Host: test.example.com' http://localhost:4566/base-path
The request above will be equivalent to the following request:
$ curl http://<your-api-id>.execute-api.localhost.localstack.cloud:4566/dev/
API Gateway Resource Browser
The LocalStack Web Application provides a Resource Browser for managing API Gateway resources. You can access the Resource Browser by opening the LocalStack Web Application in your browser and navigating to the Resources section, then clicking on API Gateway under the App Integration section.
The Resource Browser displays API Gateway V1 and API Gateway V2 resources. You can click on individual resources to view their details.
The Resource Browser allows you to perform the following actions:
- Create API: Create a new API (
V1
/V2
) by clicking on Create API button on top-right and creating a new configuration by clicking on Submit button. - Edit API: Edit the API configuration (
V1
/V2
) by clicking on Edit API button on top-right and saving the new configuration by clicking on Submit button. - Check the Resources: Click on Resources tab to view the resources associated with the API, along with their details, such as
Id
,ParentId
,Path Part
, andPath
and theirHTTP
method. - Navigate the Stages: Click on Stages tab to view the stages associated with the API, along with their details, such as
Deployment Id
,Stage Name
,Client Certificate Id
, and more. - Delete API: Delete the API configuration (
V1
/V2
) by selecting the resource, clicking on Remove Selected button on top-right and confirming the deletion by clicking on Continue button.
You can also use the Resource Browser to check out the Authorizers, Models, Request Validators, API Keys, and Usage Plans.
Examples
The following code snippets and sample applications provide practical examples of how to use API Gateway in LocalStack for various use cases:
- API Gateway with Custom Domains over our LocalStack Pro samples
- Websockets via API Gateway V2
- Serverless Container-based APIs with Amazon ECS and Amazon API Gateway
- Step-up Authentication using Amazon Cognito, DynamoDB, API Gateway Lambda Authorizer, and Lambda functions
- Serverless Microservices with Amazon API Gateway, DynamoDB, SQS, and Lambda
- Note-Taking application using AWS SDK for JavaScript, Amazon DynamoDB, Lambda, Cognito, API Gateway, and S3
- For Terraform samples, check out the LocalStack Terraform examples repository