It is easy to build and maintain large scale APIs with Amazon API Gateway. From REST to WebSockets APIs, HTTP Proxies to workloads with request transformation, authentication and validation.
One common integration for building APIs is to proxy it to an AWS Lambda. Listening to their customers feedback, Amazon went one step further and on last year re:Invent they released a new feature called HTTP APIs for Amazon API Gateway.
HTTP APIs offer the core functionality of Amazon API Gateway and are optimised for building APIs that proxy to AWS Lambda functions or HTTP backends. With cost savings up to 70% compared to REST APIs, significant performance improvements (without the Amazon API Gateway service overhead), out of the box features like throttling, metrics, logging, OIDC, OAuth and built-in support for CORS.
What is the difference between HTTP APIs and REST APIs in Amazon API Gateway?
As mentioned above, HTTP APIs are focused and optimised for APIs proxying request to an AWS Lambda or HTTP backends. Any other offers and features from REST APIs aren't available. I will list some features heres, but they are not exhaustive and can change, since Amazon can ship more (or less) features anytime.
What features ARE NOT AVAILABLE while using HTTP APIs?
- Custom Authorizers: AWS Lambda and IAM (You can use Amazon Cognito as a JWT issuer only)
- Integration: HTTP, AWS Services, Private Integration or Mocks (we can use HTTP as a proxy integration only)
- API Management: Usage Plans, API Keys, custom domains with TLS 1.0 or wildcard custom domains names.
- Development: Cache, Request transformation, Request/Response validation, Test Invocation
- Security: Client Certificates, AWS WAF, Resource policies
- API Type: Edge-optimized, Private (HTTP APIs are Regional only)
- Monitoring: Access logs to Amazon Kinesis Data Firehose, AWS X-Ray
While the list above can be scary and maybe you been thinking "...damn, that is too much, I'll keep using REST APIs". I dare you to think again, usually, we do not use 90% of the features on this list, but we would be paying for it if we misconfigured our projects.
With HTTP APIs, AWS helps us to falling into the pit of success, with enhanced performance, cheaper with great features and an easier developer experience.
This service is still in Beta, with fast improvements and moves towards General Availability. You can stay up to date following this AWS page.
Building your first HTTP API with Serverless Framework
At Serverless Guru, we love helping you to migrate, build or train your team on serverless best practices.
Last week, our official partner Serverless, released its support for HTTP APIs with Serverless Framework.
We can now leverage the awesome features of Serverless Framework to build products using all new Amazon API Gateway HTTP APIs!
Let's review the following serverless.yml
file:
service: example-http-api-service
provider:
name: aws
functions:
getItems:
handler: handler.getItems
events:
- httpApi: "GET /items"
Even with all the differences between HTTP APIs and REST APIs, Serverless Framework decided to propose a new event, httpApi
to attach functions to HTTP APIs in your serverless.yml
file, keeping the syntax familiar and easy to migrate.
Exploring the HTTP verbs, we have more routing options, like:
...
functions:
...
postItem:
handler: handler.postItem
events:
- httpApi: "POST /items"
getItem:
handler: handler.getItem
events:
- httpApi: "GET /items/{id}"
putItem:
handler: handler.putItem
events:
- httpApi: "PUT /items/{id}"
deleteItem:
handler: handler.deleteItem
events:
- httpApi: "DELETE /items/{id}"
...
If we need to customise our httpApi
event, we can use the object syntax:
...
getReceipt:
handler: handler.getReceipt
events:
- httpApi:
method: GET
path: /receipt/{receiptId}
timeout: 5
...
We can define a catch all route using:
...
catchAll:
handler: handler.catchAll
events:
- httpApi:
path: "*"
...
Protecting your routes with JWT Authorizers
By default, all endpoints are publicly accessible. To protect our routes, HTTP API supports JSON Web Tokens, commonly used by OAuth 2.0 and Native OpenID workflows, called JWT Authorizers.
We can restrict access to our endpoints by configuring a JWT Authorizer in our provider
section:
provider:
...
httpApi:
authorizers:
myCustomJwtAuthorizer:
identitySource: $request.header.Authorization
issuerUrl: https://...
audience:
- xxxx
- xxxx
To authorise your request, Amazon API Gateway uses a general workflow of 4 steps to validate your token by calling your JWT Authorizer. Make sure your issuer is following these requirements.
In case you wanna use Amazon Cognito we could use the following syntax:
provider:
...
httpApi:
authorizers:
customCognitoAuthorizer:
identitySource: $request.header.Authorization
issuerUrl: https://cognito-idp.${region}.amazonaws.com/${cognitoPoolId}
audience:
- cognitoClientIDWeb
- cognitoClientIDMobile
After declaring a JWT Authorizer, we can define which endpoints we want restrict access by configuring an authorizer
key:
functions:
...
getProfile:
handler: handler.getProfile
events:
- httpApi:
method: GET
path: /me
authorizer: customCognitoAuthorizer
If we need to extend the authorisation to include scopes to our endpoint, we can change it to:
functions:
...
getProfile:
handler: handler.getProfile
events:
- httpApi:
method: GET
path: /me
authorizer:
name: customCognitoAuthorizer
scopes:
- user.id
- user.email
Fine grain CORS control
With built-in support for CORS in HTTP API, Serverless Framework made it simple for its users by defining a cors: true
property by default:
provider:
httpApi:
cors: true
This default behaviour implies and ensure the following headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, X-Amz-Date, Authorization, X-Api-Key, X-Amz-Security-Token, X-Amz-User-Agent
-
Access-Control-Allow-Methods: OPTIONS
+ all methods you defined in your route (GET
,POST
etc)
In case you need a better control over it, you can manipulate the provider.httpApi.cors
property and define:
provider:
...
httpApi:
...
cors:
allowedOrigins:
- https://my-allow-domain.com
- https://allow-this-one.com
allowedHeaders:
- Authorization
- Content-Type
allowedMethods:
- GET
- POST
allowCredentials: true
exposedResponseHeaders:
- Special-Response-Header
maxAge: 6000 # in seconds
Turning on Access Logging
Similar to REST APIs, we can turn on access logs in HTTP API by using provider.logs.httpApi
like:
provider:
...
logs:
...
httpApi: true
If you have a particular log format, you can use the .format
property:
provider:
...
logs:
...
httpApi:
format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }'
The custom format above is used by default when you use provider.logs.httpApi: true
, but can be used as a reference in case you wanna change it.
All HTTP API options reference
To illustrate the possibilities with Serverless Framework, we can define the following options when using HTTP APIs:
provider:
httpApi:
id: ApiID # ID of externally created HTTP API to attach resources
timeout: 5
cors: true
authorizers:
myJwtAuthorizer:
identitySource: $request.header.Authorization
issuerUrl: https://cognito-idp.${region}.amazonaws.com/${cognitoPoolId}
audience:
- xxxx
- xxxx
logs:
httpApi: true
functions:
myFunction:
handler: myFunction.handler
events:
- httpApi:
method: GET
path: /url-path/{param}
timeout: 5
authorizer:
name: myJwtAuthorizer
scopes:
- user.id
- user.email
As we can see, the syntax is familiar and easy to use. Making the usage of HTTP APIs friendly and approachable for all projects already using Serverless Framework.
Conclusion
HTTP APIs are designed for low-latency, cost-effective AWS Lambda proxy and HTTP proxy APIs. HTTP APIs support OIDC and OAuth 2.0 authorization, and come with built-in support for CORS.
When should I used it?
With something quite new, it is always a hot topic! HTTP APIs main features orbiting around:
- JWT Authorizers for JWT AuthN / AuthZ
- Proxy based API, using Lambda or HTTP backend
- Built-in CORS support
If you are already using or can support JWT token, most of your requests are being proxied to an AWS Lambda and you require CORS for your clients. You should use or migrate to HTTP API. With an infrastructure optimized and enhanced for these features, you will see great cost reduction with better performance.
With this new flavour in Amazon API Gateway, the enhanced performance and lower costs can be a huge win when building JWT based APIs.
The service is still limited to a few regions, but if you deploying workloads on them already, get ready to pair it up with Serverless Framework and leverage all the advantages today!
Written by Serverless Guru Eduardo Rabelo
@oieduardorabelo
Top comments (1)
Great post! But how do you make the JWT Authorizer work with tokens issued by Cognito?? Cognito's Access Tokens have a "scope" claim, but don't have an "aud" claim (it uses "client_id" instead), and their ID Tokens have an "aud" claim but don't have a "scope" claim.