Creating an API Gateway with HTTP API
First, congratulations again on learning how to define and deploy your first serverless application!
But that's not enough for your client, the "Sauf Pompiers" folks. They also want a functional API with which they can interact, not just three isolated Lambdas in a CloudFormation stack. We can't expect them to manually invoke them, we need to expose their functionality through an API. And this requires us to use the AWS API Gateway. This section will connect on your previous work and we will create together an API that exposes an HTTP interface to all of your previous three Lambda function.
As we briefly touched before, AWS Lambda is an isolated permissionless function. Completely locked down, without any external way to access it. It doesn't run at all, unless its triggered by an event. Those events can come from various other services, such as S3 Buckets, API Gateway, AppSync GraphQL, Alexa, and many more.
So how do we create an API with AWS Lambda?
AWS API Gateway
As you could presume, API Gateway is a completely separate service from AWS Lambda. It's purpose is only to define endpoints and provide external access to HTTP requests with their appropriate response formatting, security, rate limiting, and so on. If you want to get more specific on the API Gateway, please take a look at it's Documentation
There are multiple ways of how to define an API Gateway, as a :
- separate template resource, NO Swagger
- separate template resource, WITH Swagger
- through an AWS Lambda Event trigger
Here are the definition examples
Separate API template resource NO Swagger
BasicAWSApiGateway:
Type: AWS::Serverless::Api
Properties:
Name: Basic AWS Api Gateway
StageName: Stage
Separate API template resource WITH Swagger
Here is the example with the Swagger.
GetOneApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionBody:
swagger: 2.0
info:
title:
Ref: AWS::StackName
paths:
/someitems/{id}:
get:
parameters:
- name: id
in: path
required: true
type: string
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetOneLambda.Arn}/invocations
GetOneLambda:
Type: AWS::Serverless::Function
...
Events:
Api:
Type: Api
Properties:
Path: /someitems/{id}
Method: GET
RestApiId: !Ref GetOneApi
Looks good, but its a bit too verbose, right?
AWS Lambda Event trigger
Here comes a SAM abstracted example for a Serverless Function:
YourSAMLambdaFunction
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs12.x
CodeUri: src/
Handler: index.handler
Events:
YourAPIEndpointName:
Type: API
Properties:
Path: /hello
Method: GET
RestApiId: !Ref HelloApi ## This is optional.
As you could notice, a lot simpler, but without any configuration for CORS, Stage, and so forth. Recommended for same origin domains. Tthis example is basically just adding an Event Trigger, which automatically creates the whole resource and the endpoints underneath.
The RestApiId
property points to the separate API resource you defined above.
Task
Within your SAM template, create three API GW endpoints for your Lambdas.
- The enter-expense Lambda should be a POST HTTP endpoint, which requires the following parameters:
- issuer,
- date,
- description,
- amount,
- currency
- The list-expenses Lambda should be a GET HTTP endpoint, it doesn't require any parameter.
- The update-expense Lambda should be a PUT HTTP endpoint in the format
/expenses/{expenseId}
, which requires the following parameters:- expenseId
- issuer,
- date,
- description,
- amount,
- currency
- Deploy it using SAM CLI
- Try the code from the UI
Hints
You don't have to define parameters in the Swagger for it, just add
Events
as a property to your Lambda Function properties.Quite identical to the first solution.
The main difference for the update-expense Lambda Function is that you need to pass a parameter for the expenseId in the path, while the rest go through the HTTP body.
Additional Help
Only use this if you've spent more than 10 minutes on a single task item.
ExpensesApi:
Type: AWS::Serverless::Api
...
EnterExpense:
Type: AWS::Serverless::Function
Properties:
...
Events:
SaveApi:
Type: Api
Properties:
Path: /save
Method: POST
RestApiId: !Ref ExpensesApi
ExpensesApi:
Type: AWS::Serverless::Api
...
Properties:
...
DefinitionBody:
swagger: 2.0
info:
title:
Ref: AWS::StackName
paths:
/expenses/{id}:
put:
parameters:
- name: id
in: path
required: true
type: string
responses: {}
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UpdateExpenseLambda.Arn}/invocations
UpdateExpenseLambda:
Type: AWS::Serverless::Function
Properties:
Handler: update-expense.handler
Runtime: nodejs12.x
Events:
Api:
Type: Api
Properties:
Path: /expenses/{id}
Method: PUT
RestApiId: !Ref ExpensesApi