Skip to content

Commit

Permalink
fix(cfnspec): make EndpointConfiguration of AWS::Serverless::Api a un…
Browse files Browse the repository at this point in the history
…ion type (aws#15526)

A recent update to the SAM spec (aws#15311)
changed the EndpointConfiguration property of AWS::Serverless::Api to have a complex type.
However, that is a breaking change compared to the previous, string, type.
I consulted with the SAM team, and it turns out the property accepts both a string and the complex type.
Given that, patch our SAM spec to make EndpointConfiguration a union type.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
skinny85 authored and hollanddd committed Aug 26, 2021
1 parent 3fb950d commit cc2adeb
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 2 deletions.
44 changes: 44 additions & 0 deletions packages/@aws-cdk/aws-sam/test/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import '@aws-cdk/assert-internal/jest';
import * as cdk from '@aws-cdk/core';
import * as sam from '../lib';

describe('AWS::Serverless::Api', () => {
let stack: cdk.Stack;
beforeEach(() => {
stack = new cdk.Stack();
});

test('can be created by passing a complex type to EndpointConfiguration', () => {
new sam.CfnApi(stack, 'Api', {
stageName: 'prod',
definitionBody: {
body: 'definitionBody',
},
endpointConfiguration: {
type: 'GLOBAL',
},
});

expect(stack).toHaveResourceLike('AWS::Serverless::Api', {
StageName: 'prod',
EndpointConfiguration: {
Type: 'GLOBAL',
},
});
});

test('can be created by passing a string to EndpointConfiguration', () => {
new sam.CfnApi(stack, 'Api', {
stageName: 'prod',
definitionBody: {
body: 'definitionBody',
},
endpointConfiguration: 'GLOBAL',
});

expect(stack).toHaveResourceLike('AWS::Serverless::Api', {
StageName: 'prod',
EndpointConfiguration: 'GLOBAL',
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"ResourceTypes": {
"AWS::Serverless::Api": {
"Properties": {
"EndpointConfiguration": {
"patch": {
"description": "Make the EndpointConfiguration property of AWS::Serverless::Api have a union type",
"operations": [
{
"op": "add",
"path": "/PrimitiveTypes",
"value": ["String"]
},
{
"op": "add",
"path": "/Types",
"value": ["EndpointConfiguration"]
},
{
"op": "remove",
"path": "/Type"
}
]
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,30 @@ describe('CDK Include for templates with SAM transform', () => {
loadTestFileToJsObject('only-sam-function-policies-array-ddb-crud-if.yaml'),
);
});

test('can ingest a template with a a union-type property provided as an object, and output it unchanged', () => {
includeTestTemplate(stack, 'api-endpoint-config-object.yaml');

expect(stack).toMatchTemplate(
loadTestFileToJsObject('api-endpoint-config-object.yaml'),
);
});

test('can ingest a template with a a union-type property provided as a string, and output it unchanged', () => {
includeTestTemplate(stack, 'api-endpoint-config-string.yaml');

expect(stack).toMatchTemplate(
loadTestFileToJsObject('api-endpoint-config-string.yaml'),
);
});

test('can ingest a template with a a union-type property provided as an empty string, and output it unchanged', () => {
includeTestTemplate(stack, 'api-endpoint-config-string-empty.yaml');

expect(stack).toMatchTemplate(
loadTestFileToJsObject('api-endpoint-config-string-empty.yaml'),
);
});
});

function includeTestTemplate(scope: constructs.Construct, testTemplate: string): inc.CfnInclude {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
Api:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionBody:
Body: DefinitionBody
EndpointConfiguration:
Type: GLOBAL
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
Api:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionBody:
Body: DefinitionBody
EndpointConfiguration: '' # empty string
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
Api:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionBody:
Body: DefinitionBody
EndpointConfiguration: GLOBAL
12 changes: 10 additions & 2 deletions tools/cfn2ts/lib/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,9 +585,17 @@ export default class CodeGenerator {
this.code.closeBlock();
}

this.code.line('properties = properties || {};');
this.code.line(`const ret = new ${CFN_PARSE}.FromCloudFormationPropertyObject<${typeName.fqn}>();`);
this.code.line('properties = properties == null ? {} : properties;');
// if the passed value is not an object, immediately return it,
// and let a validator report an error -
// otherwise, we'll just return an empty object for this case,
// which a validator might not catch
// (if the interface we're emitting this function for has no required properties, for example)
this.code.openBlock("if (typeof properties !== 'object')");
this.code.line(`return new ${CFN_PARSE}.FromCloudFormationResult(properties);`);
this.code.closeBlock();

this.code.line(`const ret = new ${CFN_PARSE}.FromCloudFormationPropertyObject<${typeName.fqn}>();`);
const self = this;
// class used for the visitor
class FromCloudFormationFactoryVisitor implements genspec.PropertyVisitor<string> {
Expand Down

0 comments on commit cc2adeb

Please sign in to comment.