How to use the new AWS HTTP API with SAM
Tags: serverless, aws
Published: 2019-12-06 15:51:24

Hi, I'm new to the world of serverless this year, and in my role at Solve I've been working on trying out some of the newest additions to the serverless world announced at this year's AWS re:invent to see if they suit us. 

One of these new announcements that we are stoked about is the [new HTTP API service](https://aws.amazon.com/blogs/compute/announcing-http-apis-for-amazon-api-gateway/). As our new app is to have a number of services driven out of AWS, all you had to say was 'faster' and 'up to 70% cheaper' to get our interest! To test it out we picked a service that was going to be particularly busy, and I've been trying out how to implement it with SAM. It ended up being a non-trivial fix, and there were no docs for multi-endpoint services - so I thought I'd write up what I found!

# Previously on our API... 

Our old API had a POST and GET endpoint, both to be served by lambda functions which would do call(s) to DynamoDB. The SAM template looked like this: 
```yaml
Resources:
...
  GetOneOfTheThing: 
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.getOneThing
      Events:
        GetOneThing:
          Type: Api
          Properties:
            Path: /getOneThing/{Key}/
            Method: get
            RestApiId: !Ref MyApi

  PostManyKeysForManyThings:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.postGetManyThings
      Events:
        GetVariationDetail:
          Type: Api
          Properties:
            Path: /getManyThings/
            Method: post
            RestApiId: !Ref MyApi  

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Stage
      MethodSettings:
        - ResourcePath: "/*"
          HttpMethod: "*"

```

# Initial Template Changes

Simple steps from the documentation: 
1. Change the event type from `Api` to `HttpApi` for each of the lambda objects
2. API object type from `Serverless::Api` to `Serverless::HttpApi` 
3. Remove `MethodSettings` from the API object. As [described in the docs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-httpapi.html) the properties of this object are a lot simpler than the previous one. 
For a single API endpoint, this `Serverless::HttpApi` object isn't actually needed when using SAM, as it can work out how to fill in the gaps. However, I found that when you wanted to use the HTTP API with two endpoints, this no longer caused a connection between the Lambdas and the new API. 

# Subtler Template Changes
The things that caught me out from there were:
1. I needed a `DefinitionBody` for the HttpApi object. There was no real guidance for this beyond an example of a root path option, so after some tinkering what I found to work was as follows:
```yaml
      DefinitionBody:
        info:
          title:
            Ref: AWS::StackName
          version: "1.0"
        openapi: 3.0.1
        paths:
          /getOneThing/{flagKey}:
            get:
              responses: {}
          /getManyThings:
            post:
              responses: {}
``` 
2. The catch here, was that the path options couldn't end with a `/`, therefore the lambda events' paths needed to edited to remove the trailing backslash. (i.e. `Path: /getOneThing/{flagKey}/`->`Path: /getOneThing/{flagKey}`)
```yaml
  GetOneOfTheThing: 
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.getOneThing
      Events:
        GetOneThing:
          Type: HttpApi
          Properties:
            Path: /getOneThing/{Key}
            Method: get
            RestApiId: !Ref MyApi

  PostManyKeysForManyThings:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.postGetManyThings
      Events:
        GetVariationDetail:
          Type: HttpApi
          Properties:
            Path: /getManyThings
            Method: post
            RestApiId: !Ref MyApi 
```

# Conclusion

And that was it! No changes at all to the lambdas themselves, and only one change to a test, as the sad-path test of no key being provided to the GET was no longer being caught as a 403 by API Gateway was now returning a 400 by the error catching inside the lambda. 

Caveat here of course is that HTTP API is still in beta so some of this may be subject to change, but we are looking forward to its benefits nonetheless!