Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicating paths in SAM EventSource and SAM API's DefinitionBody #1806

Open
martin-sommerseth opened this issue Nov 18, 2020 · 3 comments
Open

Comments

@martin-sommerseth
Copy link

martin-sommerseth commented Nov 18, 2020

Our team is using SAM-functions for our APIs. To define the API we use open-API-specification, and AWS does not support the option to directly connect a SAM function to the open API specification. AWS requires us to define an EventSource to specify the endpoint. This means that we have to write our endpoint specification in two places, both in open-API-spec and in EventSource for the SAM function. We will then risk that our API documentation is different from our deployed API (endpoint paths could then be different).

We would highly appreciate it if this is something you could support.

Here is an example of the template we use today. You can see that we define the paths inside the DefinitionBody for the resource ServerlessApi as well as for the SAM-functions such as Result or Status.

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Globals:
  Function:
    CodeUri:
      Bucket: !Ref SolverServiceDeploymentBucket
      Key: !Ref SolverServiceDeploymentArtifact
    Runtime: python3.7
    Timeout: 30
    MemorySize: 3008
    Tracing: Active
    Environment:
      Variables:
        SOLVER_ARTIFACT_ID: !Ref SolverId
        REQUEST_FOLDER: request
        RESULT_FOLDER: result
        BUCKET_NAME: !Sub "of-solvserv-model-result-bucket-${SolverId}-${Environment}"
        DYNAMO_DB_NAME: !Sub "of-solvserv-instMetadataDb-${SolverId}-${Environment}"
        SQS_QUEUE_NAME: !Sub "of-solverservice-startSolverQueue-${SolverId}-${Environment}"
        LD_SDK_KEY: !Ref LaunchDarklySdkKey

Resources:
  ResultLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: !Sub "of-solverservice-resultLogGroup-${SolverId}-${Environment}"

  Result:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "of-solverservice-result-${SolverId}-${Environment}"
      Handler: src/handler/result/result_handler.handle
      Policies:
        - AWSLambdaExecute
        - Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - s3:GetObject
              Resource: !Join [ '', [ !GetAtt s3helperBucket.Arn, '/result/*' ]]
            - Effect: Allow
              Action:
                - s3:ListBucket
              Resource: !GetAtt
                - s3helperBucket
                - Arn
      Events:
        ApiGatewayResourceStartwebapp:
          Type: Api
          Properties:
            Path: /result/{jobId}
            Method: GET
            RestApiId: !Ref ServerlessApi

  ServerlessApi:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        ApiKeyRequired: false
        Authorizers:
          LambdaTokenAuth:
            FunctionArn: !Ref AuthorizerLambdaArn
            FunctionPayloadType: REQUEST
            Identity:
              Headers:
                - 'Authorization'
              ReauthorizeEvery: 0
        DefaultAuthorizer: LambdaTokenAuth
      EndpointConfiguration: EDGE
      Name: !Sub "of-solverservice-apiGateway-${SolverId}-${Environment}"
      StageName: !Ref SolverId
      TracingEnabled: True
      MethodSettings:
        - MetricsEnabled: true
          DataTraceEnabled: true
          HttpMethod: "*"
          LoggingLevel: "ERROR"
          ResourcePath: "/*"
      Cors:
        AllowMethods: "POST, GET, PUT, OPTIONS"
        AllowHeaders: 'Authorization,api-version,Content-Type,if-modified-since,Accept'
      DefinitionBody:
        openapi: "3.0.1"
        info:
          title: !Sub "of-solverservice-apiGateway-${SolverId}-${Environment}"
          version: "1.0"
        servers:
          - url: "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/{basePath}"
            variables:
              basePath:
                default: !Ref SolverId
        paths:
          /result/{jobId}:
            get:
              security:
                - LambdaTokenAuth: [ ]
              x-amazon-apigateway-integration:
                uri: !Join
                  - ''
                  - - 'arn:aws:apigateway:'
                    - !Ref 'AWS::Region'
                    - ':lambda:path/2015-03-31/functions/'
                    - !GetAtt [ Result, Arn ]
                    - '/invocations'
                passthroughBehavior: "when_no_match"
                httpMethod: "POST"
                type: "aws_proxy"
            options:
              consumes:
                - application/json
              produces:
                - application/json
              responses:
                "200":
                  description: '200 response'
                  schema:
                    $ref: '#/definitions/Empty'
                  headers:
                    Access-Control-Allow-Origin:
                      type: string
                    Access-Control-Allow-Methods:
                      type: string
                    Access-Control-Allow-Headers:
                      type: string
              security:
                - NONE: []
              x-amazon-apigateway-integration:
                responses:
                  default:
                    statusCode: 200
                    responseParameters:
                      method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS,PATCH,POST,PUT'"
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,api-version,if-modified-since,Accept'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                requestTemplates:
                  application/json: '{"statusCode": 200}'
                passthroughBehavior: when_no_match
                type: mock

  ApiBasePath:
    Type: AWS::ApiGateway::BasePathMapping
    Properties:
      BasePath: !Ref SolverId
      DomainName: !Sub '${DomainSubPathApi}.${DNSName}'
      RestApiId: !Ref ServerlessApi
      Stage: !Ref ServerlessApi.Stage

@wchengru
Copy link
Contributor

Hi @martin-sommerseth , it is true that defining the path in two different is not convenient, however, the behaviour is expected.
The path property in EventSource defines the endpoint where this function is invoked (Document). It is a required property.
The DefinitionBody defines the paths of all Apis (Document), path is necessary in OpenApi definition.
If DefinitionBody is not defined in SAM template, an auto-generated DefinitionBody will take the place, but the generated one will not include the detailed OpenApi definitions your provided in this example.
Please let us know if you have more suggestions on it. Thanks!

@david-katz
Copy link

@wchengru isn't "the endpoint where this function is invoked" already defined in the openapi spec though, using the "x-amazon-apigateway-integration"? What further information does the eventSource path add here?

@hoffa
Copy link
Contributor

hoffa commented Mar 28, 2023

We could perhaps allow omitting properties in the event that can be determined from the OpenAPI definition; marking as feature request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants