amazon-web-servicesaws-serverlessserverless-application-model

When using HttpApi via SAM is the OpenApi definition the single point of truth?


I've spent the day getting up to speed with SAM and in particular the HttpApi, but have hit a brick wall. Here's what I want to achieve (the dream):

  1. Create a REST API in Open API 3 (the contract)
  2. Pass the api.yaml to HttpApi and have it generate all the boilerplate for the api
  3. Feel a warm glow now that my api docs and my api routes are always the same (as per the contract)
  4. Hand the Open API spec to the frontend guys and the backend guys and have them all nicely meet in the middle

I'm pretty sure that's how it's supposed to work anyway. But here's what is confusing me. I'm adding the integrations to my api.yaml e.g.:

get:
  summary: get item
  tags:
    - Items    
  responses:
    '200':
      description: Item returned successfully
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ItemResource'
    '404':
      $ref: '#/components/responses/NotFound'
  x-amazon-apigateway-integration:
    payloadFormatVersion: "2.0"
    type: "aws_proxy"
    httpMethod: "POST"
    uri: 
      Fn::GetAtt [GetItemFunction, Arn]
    connectionType: "INTERNET"

Now I was expecting that with this HttpApi would connect the routes in my OpenApi file with the Lambda I'm pointing to in the integration "GetItemFunction". So I could just define my Lambda like so:

  GetItemFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: get-item.handler
      Runtime: nodejs12.x

But that doesn't seem to set the routes as expected (I'm testing with "sam local start-api"). Instead to make it work I need to do this:

  GetItemFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: get-item.handler
      Runtime: nodejs12.x
      Events:
        GetAllItems:
          Type: HttpApi
          Properties:
            ApiId: !Ref MyHttpApi
            Path: /items/{id}
            Method: get

This works, but now I'm defining the routes in the template.yaml file and not the api.yaml file which for my use case defeats the purpose. It also seems to behave in exactly the same way regardless of whether I add the 'x-amazon-apigateway-integration' in the api.yaml or not.

I'm sure I'm missing something here, if someone could set me on the right path it would be greatly appreciated!


Solution

  • When you declare the connection in SAM using the eventsource, then SAM creates the permissions. If you do not use an eventsoursce then SAM does not build the permissions and API gateway does not have rights to invoke the Lambda function. If you want to manually build it then create a role in the SAM template. here is a working example (simplified to one template):

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: OpenAPI test
    
    Resources:
      MyHttpApi:
        Type: AWS::Serverless::HttpApi
        Properties:
          DefinitionBody:
            openapi: "3.0.1"
            info:
              title: "OpenAPI test"
            paths:
              /:
                get:
                  responses:
                    default:
                      description: Item returned successfully
                  x-amazon-apigateway-integration:
                    payloadFormatVersion: "2.0"
                    credentials: !GetAtt MyHttpApiRole.Arn
                    type: "aws_proxy"
                    httpMethod: "POST"
                    uri: !GetAtt GetItemFunction.Arn
                    connectionType: "INTERNET"
            x-amazon-apigateway-importexport-version: "1.0"
    
      MyHttpApiRole:
        Type: "AWS::IAM::Role"
        Properties:
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Principal:
                  Service: "apigateway.amazonaws.com"
                Action: 
                  - "sts:AssumeRole"
          Policies:
            - PolicyName: ApiDirectWriteToSQS
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  Action:
                  - lambda:InvokeFunction
                  Effect: Allow
                  Resource:
                    - !GetAtt GetItemFunction.Arn
    
      GetItemFunction:
        Type: AWS::Serverless::Function
        Properties:
          CodeUri: src/
          Handler: app.handler
          Runtime: nodejs12.x