Skip to content

Commit

Permalink
fix(apigateway): SAM CLI asset metadata missing from SpecRestApi (aws…
Browse files Browse the repository at this point in the history
…#17293)

Adds Assets metadata to RestApi resource in case if AssetApiDefinition is used. This Metadata will enable SAM
CLI to find local assets used by RestApi in the template.

It follows the same design in document [design/code-asset-metadata.md](https://github.com/aws/aws-cdk/pull/design/code-asset-metadata.md)

Fixes aws#14593

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
moelasmar authored and TikiTDO committed Feb 21, 2022
1 parent f347cb0 commit 1b867b4
Show file tree
Hide file tree
Showing 22 changed files with 94 additions and 45 deletions.
27 changes: 27 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/api-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import * as s3_assets from '@aws-cdk/aws-s3-assets';

// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
import * as cxapi from '@aws-cdk/cx-api';
import { Node } from 'constructs';
import { CfnRestApi } from './apigateway.generated';
import { IRestApi } from './restapi';
import { Construct } from '@aws-cdk/core';

/**
Expand Down Expand Up @@ -82,6 +86,15 @@ export abstract class ApiDefinition {
* assume it's initialized. You may just use it as a construct scope.
*/
public abstract bind(scope: Construct): ApiDefinitionConfig;

/**
* Called after the CFN RestApi resource has been created to allow the Api
* Definition to bind to it. Specifically it's required to allow assets to add
* metadata for tooling like SAM CLI to be able to find their origins.
*/
public bindAfterCreate(_scope: Construct, _restApi: IRestApi) {
return;
}
}

/**
Expand Down Expand Up @@ -198,4 +211,18 @@ export class AssetApiDefinition extends ApiDefinition {
},
};
}

public bindAfterCreate(scope: Construct, restApi: IRestApi) {
if (!scope.node.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) {
return; // not enabled
}

if (!this.asset) {
throw new Error('bindToResource() must be called after bind()');
}

const child = Node.of(restApi).defaultChild as CfnRestApi;
child.addMetadata(cxapi.ASSET_RESOURCE_METADATA_PATH_KEY, this.asset.assetPath);
child.addMetadata(cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY, 'BodyS3Location');
}
}
3 changes: 3 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,9 @@ export class SpecRestApi extends RestApiBase {
endpointConfiguration: this._configureEndpoints(props),
parameters: props.parameters,
});

props.apiDefinition.bindAfterCreate(this, this);

this.node.defaultChild = resource;
this.restApiId = resource.ref;
this.restApiRootResourceId = resource.attrRootResourceId;
Expand Down
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-apigateway/test/api-definition.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import '@aws-cdk/assert-internal/jest';
import * as path from 'path';
import { ResourcePart } from '@aws-cdk/assert-internal';
import * as s3 from '@aws-cdk/aws-s3';
import * as cdk from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import * as apigw from '../lib';

describe('api definition', () => {
Expand Down Expand Up @@ -73,6 +75,23 @@ describe('api definition', () => {
expect(synthesized.assets.length).toEqual(1);

});

test('asset metadata added to RestApi resource that contains Asset Api Definition', () => {
const stack = new cdk.Stack();
stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true);
const assetApiDefinition = apigw.ApiDefinition.fromAsset(path.join(__dirname, 'sample-definition.yaml'));
new apigw.SpecRestApi(stack, 'API', {
apiDefinition: assetApiDefinition,
});

expect(stack).toHaveResource('AWS::ApiGateway::RestApi', {
Metadata: {
'aws:asset:path': 'asset.68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml',
'aws:asset:property': 'BodyS3Location',
},
}, ResourcePart.CompleteDefinition);

});
});

describe('apigateway.ApiDefinition.fromBucket', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@
]
}
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyAuthorizerFunctionServiceRole8A34C19E",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"MyAuthorizerFunctionServiceRole8A34C19E"
Expand Down Expand Up @@ -313,4 +313,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const app = new App();
const stack = new Stack(app, 'RequestAuthorizerInteg');

const authorizerFn = new lambda.Function(stack, 'MyAuthorizerFunction', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.AssetCode.fromAsset(path.join(__dirname, 'integ.request-authorizer.handler')),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@
]
}
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyAuthorizerFunctionServiceRole8A34C19E",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"MyAuthorizerFunctionServiceRole8A34C19E"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const app = new App();
const stack = new Stack(app, 'TokenAuthorizerIAMRoleInteg');

const authorizerFn = new lambda.Function(stack, 'MyAuthorizerFunction', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.AssetCode.fromAsset(path.join(__dirname, 'integ.token-authorizer.handler')),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@
]
}
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyAuthorizerFunctionServiceRole8A34C19E",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"MyAuthorizerFunctionServiceRole8A34C19E"
Expand Down Expand Up @@ -313,4 +313,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const app = new App();
const stack = new Stack(app, 'TokenAuthorizerInteg');

const authorizerFn = new lambda.Function(stack, 'MyAuthorizerFunction', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.AssetCode.fromAsset(path.join(__dirname, 'integ.token-authorizer.handler')),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,14 +564,14 @@
]
}
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"handlerServiceRole187D5A5A",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"handlerServiceRole187D5A5A"
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/test/integ.cors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TestStack extends Stack {
const api = new apigw.RestApi(this, 'cors-api-test');

const handler = new lambda.Function(this, 'handler', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, 'integ.cors.handler')),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"myfnServiceRole7822DC24",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"myfnServiceRole7822DC24"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class LateBoundDeploymentStageStack extends Stack {

const fn = new Function(this, 'myfn', {
code: Code.fromInline('foo'),
runtime: Runtime.NODEJS_10_X,
runtime: Runtime.NODEJS_14_X,
handler: 'index.handler',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
"Code": {
"ZipFile": "exports.handler = function echoHandlerCode(event, _, callback) {\n return callback(undefined, {\n isBase64Encoded: false,\n statusCode: 200,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(event),\n });\n}"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"BooksHandlerServiceRole5B6A8847",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"BooksHandlerServiceRole5B6A8847"
Expand Down Expand Up @@ -87,14 +87,14 @@
"Code": {
"ZipFile": "exports.handler = function echoHandlerCode(event, _, callback) {\n return callback(undefined, {\n isBase64Encoded: false,\n statusCode: 200,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(event),\n });\n}"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"BookHandlerServiceRole894768AD",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"BookHandlerServiceRole894768AD"
Expand Down Expand Up @@ -137,14 +137,14 @@
"Code": {
"ZipFile": "exports.handler = function helloCode(_event, _context, callback) {\n return callback(undefined, {\n statusCode: 200,\n body: 'hello, world!',\n });\n}"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"HelloServiceRole1E55EA16",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"HelloServiceRole1E55EA16"
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ class BookStack extends cdk.Stack {
super(scope, id);

const booksHandler = new apigw.LambdaIntegration(new lambda.Function(this, 'BooksHandler', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`exports.handler = ${echoHandlerCode}`),
}));

const bookHandler = new apigw.LambdaIntegration(new lambda.Function(this, 'BookHandler', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`exports.handler = ${echoHandlerCode}`),
}));

const hello = new apigw.LambdaIntegration(new lambda.Function(this, 'Hello', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`exports.handler = ${helloCode}`),
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,14 +651,14 @@
"Code": {
"ZipFile": "exports.handler = function handlerCode(event, _, callback) {\n return callback(undefined, {\n isBase64Encoded: false,\n statusCode: 200,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(event),\n });\n }"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyHandlerServiceRoleFFA06653",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"MyHandlerServiceRoleFFA06653"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
"Code": {
"ZipFile": "exports.handler = async function(event) {\n return {\n 'headers': { 'Content-Type': 'text/plain' },\n 'statusCode': 200\n }\n }"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"firstLambdaServiceRoleB6408C31",
"Arn"
]
},
"Runtime": "nodejs10.x",
"FunctionName": "FirstLambda"
"FunctionName": "FirstLambda",
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"firstLambdaServiceRoleB6408C31"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class FirstStack extends cdk.Stack {
}
}`),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
"Code": {
"ZipFile": "exports.handler = function helloCode(_event, _context, callback) {\n return callback(undefined, {\n statusCode: 200,\n body: 'hello, world!',\n });\n}"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"HelloServiceRole1E55EA16",
"Arn"
]
},
"Runtime": "nodejs10.x"
"Handler": "index.handler",
"Runtime": "nodejs14.x"
},
"DependsOn": [
"HelloServiceRole1E55EA16"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class MultiStack extends cdk.Stack {
super(scope, id);

const hello = new apigw.LambdaIntegration(new lambda.Function(this, 'Hello', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`exports.handler = ${helloCode}`),
}));
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/test/integ.restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Test extends cdk.Stack {
});

const handler = new lambda.Function(this, 'MyHandler', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromInline(`exports.handler = ${handlerCode}`),
handler: 'index.handler',
});
Expand Down
Loading

0 comments on commit 1b867b4

Please sign in to comment.