How to enforce an AWS CloudFormation update of Amazon API Gateway Deployment via AWS CodePipeline

If you have ever deployed Amazon API Gateway with AWS CloudFormation (CF), you probably recognize the following code:

ApiDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref Api
StageName: !Ref Stage

This resource creates a deployment for Amazon API Gateway, which practically means, that it publishes the referenced API Gateway.

Everything works just fine, until you make a change into the API and update the CF stack. Although the API Gateway resources were changed, your client sees always the same old API.

The problem is, from the template point of view, there is no change in the Deployment resource, it means there was no new deployment proceeded.

Well, this is pretty sad. Probably the best possible solution you can find is to add a new parameter into the CF template and use it somehow in the Deployment resource:

Parameters: 
ApiVersion:
Type: String
Description: "API version for deployment."
Default: "1.0.0"
...
Resources:
...
ApiDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
Description: !Sub "API Version: ${ApiVersion}"
RestApiId: !Ref Api
StageName: !Ref Stage

The drawback of this approach is the need to change the value everytime you deploy a new version of the API.

Another problem comes, when you deploy the API with help of some continuous delivery process (and you definitely should!), for example via AWS CodePipeline.

A pipeline is triggered by a source code change and proceeds the deployment step by step. Now you have to figure out, how to change the API version value by the pipeline.

You need a value unique for every change. Unfortunately, AWS CodePipeline doesn’t provide any Timestamp function you could use. The easiest way is to use the artifact hash, created by the pipeline.

Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
...
Stages:
- Name: Source
Actions:
- Name: codebase
InputArtifacts: []
OutputArtifacts:
- Name: SourceArtifact
...
- Name: Staging
Actions:
- Name: stage
InputArtifacts:
- Name: SourceArtifact
OutputArtifacts: []
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
StackName: ...
ActionMode: CREATE_UPDATE
Capabilities: CAPABILITY_NAMED_IAM
TemplatePath: !Sub "SourceArtifact::cf/template.yml"
ParameterOverrides: !Sub |
{
"ApiVersion" : { "Fn::GetArtifactAtt" : ["SourceArtifact", "ObjectKey"] }
}
...

Generally, any artifact can be used, but the Source is always present, so you don’t have to think about it.

The parameter value doesn’t look very nice, but while understanding it as a unique hash with no particular meaning, it fulfils its task well.

Software developer and occasional blogger: https://blog.ttulka.com