When using a Swagger file to define an API, users have to explicitly specify Stage Variables to hold the Lambda function ARN and use the stage variable in their Swagger template to specify the integration. This is not intuitive.
We could simplify this process by automatically injecting the Stage Variable when users specify an API Event source to their Lambda Function
When customers specify a template like this:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs4.3
Events:
GetApi:
Type: API
Properties:
Path: /
Method: GET
RestApiId: !Ref MyApiResource
MyApiResource:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: s3://bucket/myswagger.yaml
we could inject a StageVariable to the API resource where variable name is equal to the function resource's logical name and value equal to the function's ARN
MyApiResource:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: s3://bucket/myswagger.yaml
Variables:
LambdaFunction: !Ref LambdaFunction
_examples/2016-10-31/api_swagger_cors_ seems to inject the function logical name. Could we somehow get the full ARN such that we don't have to hard-code region and accountId into Swagger (or defining them as stage variables) as well? Thanks
Yes, getting the full ARN would be useful. This will solve my problem with using a stage variable for the account ID - #87
Our current cheapo workaround (since we cannot use the inlined body directly in other tools like Swagger Editor, or for input validation) is to maintain a separate swagger.yaml, but format everything as if it was inside the SAM template (i.e. we can reference parameters through ${} syntax).
We then terminate the actual SAM template with the Api resource, but instead of specifying a value of the DefinitionBody as the last parameter (after an obvious !Sub |-), we concatenate the Swagger file before packaging the application (YAML lets you do that if you also properly indent all lines of the Swagger file, either explicitly in the file or using a regular expression in gulp-replace or something similar).
Nice, it seems like now we will be able to use http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/create-reusable-transform-function-snippets-and-add-to-your-template-with-aws-include-transform.html to directly insert the Swagger YAML stored on S3 (but before any substitutions are made). Will report back once I test it.
Eager to see what possible with include transform, wonder if they will allow you to point to a local template like aws package does.
Finally got it working! In my SAM template:
Api:
Type: AWS::Serverless::Api
Properties:
StageName: Latest
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: !Sub s3://${ArtifactsBucket}/swagger.yaml
where ArtifactsBucket refers to the bucket where I upload my Swagger spec prior to 'packaging' the SAM template. Then, in the Swagger template itself I can use the intrinsics, e.g.
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetProjects.Arn}/invocations
I'm using the long Fn::Sub notation here instead of just !Sub, because Swagger doesn't natively support the latter, and also because the docs on AWS::Include Transform say that shorthand forms are not supported yet.
On a side note, just wasted ~4 hours troubleshooting the Invalid ARN specified in the request error, thinking that Fn::Sub for function ARNs doesn't work. Turns out, I only forgot to prepend an ARN reference for authorizerCredentials role in the spec (I'm using a custom authorizer). I really wish API Gateway import errors were more informative! Like specifying the concrete line that fails.. In any case, just make sure to prepend Fn::Sub/Fn::Ref/Fn::GetAtt to ALL of your CloudFormation references in the spec.
P.S. Not sure about local references, that would be awesome though!
Any update on using local reference with AWS::Include?
Also, I tried passing in the Lambda ARN and the region as stage variables as shown above by @sanathkr, but this did not work. Still got an "Invalid ARN specified in the request" error. Is this pattern no longer supported?
I tried the stage variables approach too and it did not work for me either. Will try the approach @dinvlad suggested.
@dinvlad your approach looks great, but is there a way to avoid the manual swagger file upload? I would rather reference a local file (as I'm currently doing with DefinitionUri), and I'd expect cloudformation package to take care of the packaging for me.
Does it make sense? Am I missing something obvious?
@alexcasalboni agreed, that would be awesome. I don't think CF currently supports that though. package might though, but that is part of CLI so perhaps we should ask there.
Also, you can paste your entire swagger inside CF template, and reference variables the same way. But that blows up the size of the SAM template, which is currently limited to 51.2 KB (last time I checked).
@dinvlad Yes, that's what I'm doing right now. Inlining a small API sounded reasonable.
And thanks for the template size limit, that's good to know!
Note that, at least for me, the method @dinvlad recommends doesn't work if the Include'd Swagger file is > whatever the size limit is. Gets the following error in CF console:
Errors found during import: Unable to put integration on 'GET' for resource at path '/account': The item is too large. Please reduce the item size.
Template size limit is 460KB if you upload it to S3 and pass the S3 URL to CloudFormation.
I don't see us doing this at the moment for external swagger files. Best is to either inline the Swagger file or use AWS::Include to let CloudFormation inline the file on runtime.
Most helpful comment
Finally got it working! In my SAM template:
where
ArtifactsBucketrefers to the bucket where I upload my Swagger spec prior to 'packaging' the SAM template. Then, in the Swagger template itself I can use the intrinsics, e.g.I'm using the long
Fn::Subnotation here instead of just!Sub, because Swagger doesn't natively support the latter, and also because the docs onAWS::IncludeTransform say that shorthand forms are not supported yet.On a side note, just wasted ~4 hours troubleshooting the
Invalid ARN specified in the requesterror, thinking thatFn::Subfor function ARNs doesn't work. Turns out, I only forgot to prepend an ARN reference forauthorizerCredentialsrole in the spec (I'm using a custom authorizer). I really wish API Gateway import errors were more informative! Like specifying the concrete line that fails.. In any case, just make sure to prependFn::Sub/Fn::Ref/Fn::GetAttto ALL of your CloudFormation references in the spec.P.S. Not sure about local references, that would be awesome though!