Hello,
I would like to reference inside the serverless.yml to an external swagger api definition.
Swagger is a widely spread way to define an api and it’s also supported from the api gateway to import external swagger definitions.
With a swagger api definition there can also be added aws features like api validation and custom api resonses to the api gateway, which will replace a lot of small serverless plugins with official aws features. Also, it gives a developer the possibility to use his api definition from other projects directly with the serverless framework and convert the project easier to serverless.
My current approach is to overwrite the serverless api with the aws put-rest-api command, but it’s not the optimal way to use my own api definition.
A similar feature was also requested in this post " Swagger and Serverless in parallel - bad idea?" but there was no solution and the there mentioned plugin looks like, that it will not be developed further.
It would be nice if I can define an api-definition path directly to the serverless resources, which would be used than to create the api-gateway.
This import my api.yml like expected but it also removes a lot of advantages, the serverless framework gives me.
If I replace the whole API template with my API definition, I also have to define all other API ressources like the API keys, the API deployment and the trigger for the lambda functions by my self.
For me, an better solution would be, if I could use something like the put-rest-api command in cloudformation to overwrite only the Methods and Models from the serverless API template and keep the API Keys and lambda trigger.
Thanks for moving this discussion forward.
My organisation is API therefore Swagger first, rather than Function therefore Serverless first.
If we can achieve the successful marriage of the two (Swagger and Serverless) then I will win them over with Serverless, without it reluctantly I’m likely destined for Swagger/SAM.
The Swagger use case the organisation likes is the ability to forward engineer the consumer/client.
You don’t need to replace the whole template. The Serverless Framework will merge your resources section with the one it generates. My example adds the Body property to the CloudFormation generated by the Serverless Framework.
I’m testing your trick by including the following swagger definition in the resource section:
openapi: 3.0.0
info:
title: Sample API
description: Description
version: 0.1.9
paths:
/users:
get:
summary: Returns a list of users.
description: Optional description
responses:
'200':
description: A JSON array of user names
content:
application/json:
schema:
type: array
items:
type: string
However, when I serverless deploy my API, I get the following error message:
An error occurred: ApiGatewayDeployment1554726393541 - No integration defined for method (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: ...).
Should I add x-amazon-apigateway-integration ?
Is there a way that serverless still handles the integration layer for us ?
My second question is:
Using swagger, how does serverless map the routes from the swagger definition, to the JS methods ?
I mean the swagger equivalent to the handler key-value pair:
@thomas-ama, I’m running into the same issue you are now having
I have defined by swagger documentation and included it in the Body attribute of the ApiGatewayRestApi Resource section, but am getting An error occurred: ApiGatewayDeployment1554726393541 - No integration defined for method (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: ...).
Late to the party here but this thread was very helpful. Some documentation on how Serverless merges the resources would be helpful - my google fu hasn’t found anything particularly substantial yet.
@LucasRudd , I ran into this as well when doing SAM. The x-amazon-apigateway-integration property can be added to a path and use intrinsic functions:
I have been trying to get this working also. If you define all of your API endpoints in your swagger/openAPI specification, and include the x-amazon-apigateway-integration properties to associate endpoints with lambda functions as Ashpabb suggests, then you would not have any http event definitions on your functions (in the “functions” section of serverless.yml), because the relationship between the lambda functions and the API endpoints is defined in the swagger/openAPI spec. Indeed, if you do define http events for functions with the same endpoint names as in the swagger spec then you’ll get a Another resource with the same parent already has this name error from Serverless upon deployment. But if you don’t have any http event definitions, then Serverless does not create an API for you, so you have to do it all yourself in Cloudformation:
create the API based on the swagger/openAPI spec
grant the API permission to execute the defined functions
deploy the API
@buggy you say that Serverless will merge your resources with the one it generates, but it seems to me that it won’t generate any API resources in this scenario. You could add a dummy http event to your functions in order to prompt Serverless to create the API, the permissions and the deployment, but that’d leave a dummy endpoint lying around. So I think @Dragonil was correct when stating that this approach requires the developer to define all the API resources themselves when using a swagger/openAPI specification.
Here is the Cloudformation that I added to serverless.yml to get it working with a swagger specification:
functions:
fetchData:
handler: fetchDataLambda.handler
resources:
Resources:
# Create the API based on the OpenAPI specification
ApiGatewayRestApi:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Body:
${file(./openApiSpecification.yml)}
# Deploy the API
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId:
Ref: ApiGatewayRestApi
StageName: ${self:provider.stage}
# Grant permission for the API to call the lambda - note that lambda named "fetchData"
# earlier in this file becomes "FetchDataLambdaFunction" in Cloudformation
Permission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt:
- FetchDataLambdaFunction
- Arn
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
And the relevant part of my swagger spec looks like this:
I appreciate this question was asked a long time ago, and perhaps there is a better approach now. If so, I’d love to hear about it. There doesn’t seem to be a lot of documentation around how to get a swagger/openAPI spec working within a Serverless application.
This solution was the one I was looking for! Thank you very much.
As a complement, for those who are trying to add more than 1 lambda function, in your swagger.yaml you need to add the reference to any endpoint that implements a lambda with the “x-amazon-apigateway-integration” extention, and within your serverless.yaml you can specify another “Permission” key with a variant name, like “PermissionLambdaOne, PermissionLambdaTwo” and provide the lambda name for each lambda you are building.
Also I can say that I’ve tested plugins like “serverless-swagger-api” but it didn’t function as expected. We’ll appreciate if these plugins were officialy supported by serverless, to make API building much more powerfull.
@salvadornava01 Tremendous! Thank-you! I’m going through this right now and you just saved me hours of work! Let me know if I can ever repay the favor!
@salvadornava01 I’m trying this solution and encountered "The CloudFormation template is invalid: Template error: instance of Fn::GetAtt references undefined resource "
If you overwrite the Body property of the API Gateway created by serverless in resources/extensions section, you will have all the definition of the swagger file included and you won’t have to create the API Gateway from scratch. The only bad thing is that you won’t be able to test locally.