serverless-application-model
serverless-application-model copied to clipboard
Duplicating paths in SAM EventSource and SAM API's DefinitionBody
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
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!
@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?
We could perhaps allow omitting properties in the event that can be determined from the OpenAPI definition; marking as feature request.