diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 69d3d67584ea8..8a6255b6d617d 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -652,6 +652,7 @@ export class SpecRestApi extends RestApiBase { bodyS3Location: apiDefConfig.inlineDefinition ? undefined : apiDefConfig.s3Location, endpointConfiguration: this._configureEndpoints(props), parameters: props.parameters, + disableExecuteApiEndpoint: props.disableExecuteApiEndpoint, }); props.apiDefinition.bindAfterCreate(this, this); diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.spec-restapi.ts b/packages/@aws-cdk/aws-apigateway/test/integ.spec-restapi.ts new file mode 100644 index 0000000000000..512fc8dd8e91c --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.spec-restapi.ts @@ -0,0 +1,92 @@ +import * as path from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import * as apigateway from '../lib'; + +class Test extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const api = new apigateway.SpecRestApi(this, 'my-api', { + apiDefinition: apigateway.ApiDefinition.fromAsset(path.join(__dirname, 'sample-definition.yaml')), + disableExecuteApiEndpoint: true, + retainDeployments: true, + cloudWatchRole: true, + deployOptions: { + cacheClusterEnabled: true, + stageName: 'beta', + description: 'beta stage', + loggingLevel: apigateway.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + methodOptions: { + '/api/appliances/GET': { + cachingEnabled: true, + }, + }, + }, + }); + + const handler = new lambda.Function(this, 'MyHandler', { + runtime: lambda.Runtime.NODEJS_14_X, + code: lambda.Code.fromInline(`exports.handler = ${handlerCode}`), + handler: 'index.handler', + }); + + const v1 = api.root.addResource('v1'); + + const integration = new apigateway.LambdaIntegration(handler); + + const toys = v1.addResource('toys'); + const getToysMethod: apigateway.Method = toys.addMethod('GET', integration, { apiKeyRequired: true }); + toys.addMethod('POST'); + toys.addMethod('PUT'); + + const appliances = v1.addResource('appliances'); + appliances.addMethod('GET'); + + const books = v1.addResource('books'); + books.addMethod('GET', integration); + books.addMethod('POST', integration); + + function handlerCode(event: any, _: any, callback: any) { + return callback(undefined, { + isBase64Encoded: false, + statusCode: 200, + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(event), + }); + } + + const key = api.addApiKey('ApiKey'); + const plan = api.addUsagePlan('UsagePlan', { + name: 'Basic', + apiKey: key, + description: 'Free tier monthly usage plan', + throttle: { rateLimit: 5 }, + quota: { + limit: 10000, + period: apigateway.Period.MONTH, + }, + }); + plan.addApiStage({ + stage: api.deploymentStage, + throttle: [ + { + method: getToysMethod, + throttle: { + rateLimit: 10, + burstLimit: 2, + }, + }, + ], + }); + } +} + +const app = new cdk.App(); + +const testCase = new Test(app, 'test-apigateway-spec-restapi'); +new IntegTest(app, 'apigateway-spec-restapi', { + testCases: [testCase], +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts b/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts index effde882e6497..5df01e1b71338 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts @@ -1150,7 +1150,21 @@ describe('restapi', () => { }); }); - test('"disableExecuteApiEndpoint" can disable the default execute-api endpoint', () => { + test('disableExecuteApiEndpoint is false when set to false in RestApi', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.RestApi(stack, 'my-api', { disableExecuteApiEndpoint: false }); + api.root.addMethod('GET'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::RestApi', { + DisableExecuteApiEndpoint: false, + }); + }); + + test('disableExecuteApiEndpoint is true when set to true in RestApi', () => { // GIVEN const stack = new Stack(); @@ -1164,6 +1178,39 @@ describe('restapi', () => { }); }); + test('disableExecuteApiEndpoint is false when set to false in SpecRestApi', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.SpecRestApi(stack, 'my-api', { + apiDefinition: apigw.ApiDefinition.fromInline({ foo: 'bar' }), + disableExecuteApiEndpoint: false, + }); + api.root.addMethod('GET'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::RestApi', { + DisableExecuteApiEndpoint: false, + }); + }); + + test('disableExecuteApiEndpoint is true when set to true in SpecRestApi', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.SpecRestApi(stack, 'my-api', { + apiDefinition: apigw.ApiDefinition.fromInline({ foo: 'bar' }), + disableExecuteApiEndpoint: true, + }); + api.root.addMethod('GET'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::RestApi', { + DisableExecuteApiEndpoint: true, + }); + }); describe('Description', () => { test('description can be set', () => { diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets.json new file mode 100644 index 0000000000000..7c4a2beda03b5 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.template.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/apigatewayspecrestapiDefaultTestDeployAssertD16AA485.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/asset.68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/asset.68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml new file mode 100644 index 0000000000000..a0dd197f67c37 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/asset.68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml @@ -0,0 +1,30 @@ +openapi: "3.0.2" +info: + version: 1.0.0 + title: Test API for CDK +paths: + /pets: + get: + summary: Test Method + operationId: testMethod + responses: + "200": + description: A paged array of pets + content: + application/json: + schema: + $ref: "#/components/schemas/Empty" + x-amazon-apigateway-integration: + responses: + default: + statusCode: "200" + requestTemplates: + application/json: "{\"statusCode\": 200}" + passthroughBehavior: when_no_match + type: mock + +components: + schemas: + Empty: + title: Empty Schema + type: object \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/integ.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/integ.json new file mode 100644 index 0000000000000..f4c240596beb4 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "apigateway-spec-restapi/DefaultTest": { + "stacks": [ + "test-apigateway-spec-restapi" + ], + "assertionStack": "apigateway-spec-restapi/DefaultTest/DeployAssert", + "assertionStackName": "apigatewayspecrestapiDefaultTestDeployAssertD16AA485" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..615066d18ff38 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/manifest.json @@ -0,0 +1,267 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-apigateway-spec-restapi.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-apigateway-spec-restapi.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-apigateway-spec-restapi": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-apigateway-spec-restapi.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/551655898503491ac7795f943b15b78ff3cd7b88de0661f6b5a09b11ec6976f6.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "test-apigateway-spec-restapi.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "test-apigateway-spec-restapi.assets" + ], + "metadata": { + "/test-apigateway-spec-restapi/my-api/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapi4C7BF186" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv113487378" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysA55FCBC4" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysGETApiPermissiontestapigatewayspecrestapimyapiA4A36FD7GETv1toysE7114441" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysGETApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7GETv1toys468023A4" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysGET7348114D" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/POST/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysPOST55128058" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/toys/PUT/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1toysPUT59AFBBC2" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/appliances/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1appliances507FEFF4" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/appliances/GET/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1appliancesGET8FE872EC" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1books1D4BE6C1" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/GET/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksGETApiPermissiontestapigatewayspecrestapimyapiA4A36FD7GETv1books1BA6FE85" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/GET/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksGETApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7GETv1booksC9F2D354" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/GET/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksGETC6B996D0" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/POST/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksPOSTApiPermissiontestapigatewayspecrestapimyapiA4A36FD7POSTv1books555D819D" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/POST/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksPOSTApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7POSTv1booksF101DFF9" + } + ], + "/test-apigateway-spec-restapi/my-api/Default/v1/books/POST/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1booksPOST53E2832E" + } + ], + "/test-apigateway-spec-restapi/my-api/Deployment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiDeployment92F2CB49e2ce3595b92ff44fad021c2e55149db1" + } + ], + "/test-apigateway-spec-restapi/my-api/DeploymentStage.beta/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiDeploymentStagebeta96434BEB" + } + ], + "/test-apigateway-spec-restapi/my-api/Endpoint": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiEndpoint3628AFE3" + } + ], + "/test-apigateway-spec-restapi/my-api/CloudWatchRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiCloudWatchRole095452E5" + } + ], + "/test-apigateway-spec-restapi/my-api/Account": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiAccountEC421A0A" + } + ], + "/test-apigateway-spec-restapi/my-api/ApiKey/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiApiKey43446CCF" + } + ], + "/test-apigateway-spec-restapi/my-api/UsagePlan/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiUsagePlan56F9C4F2" + } + ], + "/test-apigateway-spec-restapi/my-api/UsagePlan/UsagePlanKeyResource:testapigatewayspecrestapimyapiApiKey950FF760": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiUsagePlanUsagePlanKeyResourcetestapigatewayspecrestapimyapiApiKey950FF760D8BD56CA" + } + ], + "/test-apigateway-spec-restapi/MyHandler/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyHandlerServiceRoleFFA06653" + } + ], + "/test-apigateway-spec-restapi/MyHandler/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyHandler6B74D312" + } + ], + "/test-apigateway-spec-restapi/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/test-apigateway-spec-restapi/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "test-apigateway-spec-restapi" + }, + "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "apigatewayspecrestapiDefaultTestDeployAssertD16AA485": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "apigatewayspecrestapiDefaultTestDeployAssertD16AA485.assets" + ], + "metadata": { + "/apigateway-spec-restapi/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/apigateway-spec-restapi/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "apigateway-spec-restapi/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.assets.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.assets.json new file mode 100644 index 0000000000000..193341ba31c89 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.assets.json @@ -0,0 +1,32 @@ +{ + "version": "21.0.0", + "files": { + "68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb": { + "source": { + "path": "asset.68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "551655898503491ac7795f943b15b78ff3cd7b88de0661f6b5a09b11ec6976f6": { + "source": { + "path": "test-apigateway-spec-restapi.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "551655898503491ac7795f943b15b78ff3cd7b88de0661f6b5a09b11ec6976f6.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.template.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.template.json new file mode 100644 index 0000000000000..77d098581aa9a --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/test-apigateway-spec-restapi.template.json @@ -0,0 +1,742 @@ +{ + "Resources": { + "myapi4C7BF186": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "BodyS3Location": { + "Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "Key": "68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml" + }, + "DisableExecuteApiEndpoint": true, + "Name": "my-api" + } + }, + "myapiv113487378": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "myapi4C7BF186", + "RootResourceId" + ] + }, + "PathPart": "v1", + "RestApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "myapiv1toysA55FCBC4": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Ref": "myapiv113487378" + }, + "PathPart": "toys", + "RestApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "myapiv1toysGETApiPermissiontestapigatewayspecrestapimyapiA4A36FD7GETv1toysE7114441": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/GET/v1/toys" + ] + ] + } + } + }, + "myapiv1toysGETApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7GETv1toys468023A4": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/GET/v1/toys" + ] + ] + } + } + }, + "myapiv1toysGET7348114D": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "GET", + "ResourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "ApiKeyRequired": true, + "AuthorizationType": "NONE", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + } + } + } + }, + "myapiv1toysPOST55128058": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "POST", + "ResourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK" + } + } + }, + "myapiv1toysPUT59AFBBC2": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "PUT", + "ResourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK" + } + } + }, + "myapiv1appliances507FEFF4": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Ref": "myapiv113487378" + }, + "PathPart": "appliances", + "RestApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "myapiv1appliancesGET8FE872EC": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "GET", + "ResourceId": { + "Ref": "myapiv1appliances507FEFF4" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK" + } + } + }, + "myapiv1books1D4BE6C1": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Ref": "myapiv113487378" + }, + "PathPart": "books", + "RestApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "myapiv1booksGETApiPermissiontestapigatewayspecrestapimyapiA4A36FD7GETv1books1BA6FE85": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/GET/v1/books" + ] + ] + } + } + }, + "myapiv1booksGETApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7GETv1booksC9F2D354": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/GET/v1/books" + ] + ] + } + } + }, + "myapiv1booksGETC6B996D0": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "GET", + "ResourceId": { + "Ref": "myapiv1books1D4BE6C1" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "AuthorizationType": "NONE", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + } + } + } + }, + "myapiv1booksPOSTApiPermissiontestapigatewayspecrestapimyapiA4A36FD7POSTv1books555D819D": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/POST/v1/books" + ] + ] + } + } + }, + "myapiv1booksPOSTApiPermissionTesttestapigatewayspecrestapimyapiA4A36FD7POSTv1booksF101DFF9": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/POST/v1/books" + ] + ] + } + } + }, + "myapiv1booksPOST53E2832E": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "POST", + "ResourceId": { + "Ref": "myapiv1books1D4BE6C1" + }, + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "AuthorizationType": "NONE", + "Integration": { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + } + } + } + }, + "myapiDeployment92F2CB49e2ce3595b92ff44fad021c2e55149db1": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "myapiv1appliancesGET8FE872EC", + "myapiv1appliances507FEFF4", + "myapiv1booksGETC6B996D0", + "myapiv1booksPOST53E2832E", + "myapiv1books1D4BE6C1", + "myapiv113487378", + "myapiv1toysGET7348114D", + "myapiv1toysPOST55128058", + "myapiv1toysPUT59AFBBC2", + "myapiv1toysA55FCBC4" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "myapiDeploymentStagebeta96434BEB": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "CacheClusterEnabled": true, + "CacheClusterSize": "0.5", + "DeploymentId": { + "Ref": "myapiDeployment92F2CB49e2ce3595b92ff44fad021c2e55149db1" + }, + "Description": "beta stage", + "MethodSettings": [ + { + "DataTraceEnabled": true, + "HttpMethod": "*", + "LoggingLevel": "INFO", + "ResourcePath": "/*" + }, + { + "CachingEnabled": true, + "DataTraceEnabled": false, + "HttpMethod": "GET", + "ResourcePath": "/~1api~1appliances" + } + ], + "StageName": "beta" + } + }, + "myapiCloudWatchRole095452E5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "myapiAccountEC421A0A": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "myapiCloudWatchRole095452E5", + "Arn" + ] + } + }, + "DependsOn": [ + "myapi4C7BF186" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "myapiApiKey43446CCF": { + "Type": "AWS::ApiGateway::ApiKey", + "Properties": { + "Enabled": true, + "StageKeys": [ + { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "StageName": { + "Ref": "myapiDeploymentStagebeta96434BEB" + } + } + ] + } + }, + "myapiUsagePlan56F9C4F2": { + "Type": "AWS::ApiGateway::UsagePlan", + "Properties": { + "ApiStages": [ + { + "ApiId": { + "Ref": "myapi4C7BF186" + }, + "Stage": { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "Throttle": { + "/v1/toys/GET": { + "BurstLimit": 2, + "RateLimit": 10 + } + } + } + ], + "Description": "Free tier monthly usage plan", + "Quota": { + "Limit": 10000, + "Period": "MONTH" + }, + "Throttle": { + "RateLimit": 5 + }, + "UsagePlanName": "Basic" + } + }, + "myapiUsagePlanUsagePlanKeyResourcetestapigatewayspecrestapimyapiApiKey950FF760D8BD56CA": { + "Type": "AWS::ApiGateway::UsagePlanKey", + "Properties": { + "KeyId": { + "Ref": "myapiApiKey43446CCF" + }, + "KeyType": "API_KEY", + "UsagePlanId": { + "Ref": "myapiUsagePlan56F9C4F2" + } + } + }, + "MyHandlerServiceRoleFFA06653": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyHandler6B74D312": { + "Type": "AWS::Lambda::Function", + "Properties": { + "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 }" + }, + "Role": { + "Fn::GetAtt": [ + "MyHandlerServiceRoleFFA06653", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyHandlerServiceRoleFFA06653" + ] + } + }, + "Outputs": { + "myapiEndpoint3628AFE3": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "myapi4C7BF186" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/tree.json b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/tree.json new file mode 100644 index 0000000000000..241e0aab49369 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/spec-restapi.integ.snapshot/tree.json @@ -0,0 +1,1151 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.102" + } + }, + "test-apigateway-spec-restapi": { + "id": "test-apigateway-spec-restapi", + "path": "test-apigateway-spec-restapi", + "children": { + "my-api": { + "id": "my-api", + "path": "test-apigateway-spec-restapi/my-api", + "children": { + "APIDefinition": { + "id": "APIDefinition", + "path": "test-apigateway-spec-restapi/my-api/APIDefinition", + "children": { + "Stage": { + "id": "Stage", + "path": "test-apigateway-spec-restapi/my-api/APIDefinition/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "test-apigateway-spec-restapi/my-api/APIDefinition/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::RestApi", + "aws:cdk:cloudformation:props": { + "bodyS3Location": { + "bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "key": "68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb.yaml" + }, + "disableExecuteApiEndpoint": true, + "name": "my-api" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnRestApi", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "test-apigateway-spec-restapi/my-api/Default", + "children": { + "v1": { + "id": "v1", + "path": "test-apigateway-spec-restapi/my-api/Default/v1", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", + "aws:cdk:cloudformation:props": { + "parentId": { + "Fn::GetAtt": [ + "myapi4C7BF186", + "RootResourceId" + ] + }, + "pathPart": "v1", + "restApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnResource", + "version": "0.0.0" + } + }, + "toys": { + "id": "toys", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", + "aws:cdk:cloudformation:props": { + "parentId": { + "Ref": "myapiv113487378" + }, + "pathPart": "toys", + "restApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnResource", + "version": "0.0.0" + } + }, + "GET": { + "id": "GET", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/GET", + "children": { + "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys": { + "id": "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/GET/v1/toys" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys": { + "id": "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.toys", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/GET/v1/toys" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/GET/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "GET", + "resourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "apiKeyRequired": true, + "authorizationType": "NONE", + "integration": { + "type": "AWS_PROXY", + "uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + }, + "integrationHttpMethod": "POST" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + }, + "POST": { + "id": "POST", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/POST", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/POST/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "POST", + "resourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "authorizationType": "NONE", + "integration": { + "type": "MOCK" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + }, + "PUT": { + "id": "PUT", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/PUT", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/toys/PUT/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "PUT", + "resourceId": { + "Ref": "myapiv1toysA55FCBC4" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "authorizationType": "NONE", + "integration": { + "type": "MOCK" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Resource", + "version": "0.0.0" + } + }, + "appliances": { + "id": "appliances", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/appliances", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/appliances/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", + "aws:cdk:cloudformation:props": { + "parentId": { + "Ref": "myapiv113487378" + }, + "pathPart": "appliances", + "restApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnResource", + "version": "0.0.0" + } + }, + "GET": { + "id": "GET", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/appliances/GET", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/appliances/GET/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "GET", + "resourceId": { + "Ref": "myapiv1appliances507FEFF4" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "authorizationType": "NONE", + "integration": { + "type": "MOCK" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Resource", + "version": "0.0.0" + } + }, + "books": { + "id": "books", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", + "aws:cdk:cloudformation:props": { + "parentId": { + "Ref": "myapiv113487378" + }, + "pathPart": "books", + "restApiId": { + "Ref": "myapi4C7BF186" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnResource", + "version": "0.0.0" + } + }, + "GET": { + "id": "GET", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/GET", + "children": { + "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books": { + "id": "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/GET/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/GET/v1/books" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books": { + "id": "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/GET/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.GET..v1.books", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/GET/v1/books" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/GET/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "GET", + "resourceId": { + "Ref": "myapiv1books1D4BE6C1" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "authorizationType": "NONE", + "integration": { + "type": "AWS_PROXY", + "uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + }, + "integrationHttpMethod": "POST" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + }, + "POST": { + "id": "POST", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/POST", + "children": { + "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books": { + "id": "ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/POST/ApiPermission.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/", + { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "/POST/v1/books" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books": { + "id": "ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/POST/ApiPermission.Test.testapigatewayspecrestapimyapiA4A36FD7.POST..v1.books", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", + "aws:cdk:cloudformation:props": { + "action": "lambda:InvokeFunction", + "functionName": { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "principal": "apigateway.amazonaws.com", + "sourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "myapi4C7BF186" + }, + "/test-invoke-stage/POST/v1/books" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Default/v1/books/POST/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "POST", + "resourceId": { + "Ref": "myapiv1books1D4BE6C1" + }, + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "authorizationType": "NONE", + "integration": { + "type": "AWS_PROXY", + "uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MyHandler6B74D312", + "Arn" + ] + }, + "/invocations" + ] + ] + }, + "integrationHttpMethod": "POST" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Method", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.ResourceBase", + "version": "0.0.0" + } + }, + "Deployment": { + "id": "Deployment", + "path": "test-apigateway-spec-restapi/my-api/Deployment", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/Deployment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Deployment", + "aws:cdk:cloudformation:props": { + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "description": "Automatically created by the RestApi construct" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnDeployment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Deployment", + "version": "0.0.0" + } + }, + "DeploymentStage.beta": { + "id": "DeploymentStage.beta", + "path": "test-apigateway-spec-restapi/my-api/DeploymentStage.beta", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/DeploymentStage.beta/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage", + "aws:cdk:cloudformation:props": { + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "cacheClusterEnabled": true, + "cacheClusterSize": "0.5", + "deploymentId": { + "Ref": "myapiDeployment92F2CB49e2ce3595b92ff44fad021c2e55149db1" + }, + "description": "beta stage", + "methodSettings": [ + { + "httpMethod": "*", + "resourcePath": "/*", + "dataTraceEnabled": true, + "loggingLevel": "INFO" + }, + { + "httpMethod": "GET", + "resourcePath": "/~1api~1appliances", + "cachingEnabled": true, + "dataTraceEnabled": false + } + ], + "stageName": "beta" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnStage", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.Stage", + "version": "0.0.0" + } + }, + "Endpoint": { + "id": "Endpoint", + "path": "test-apigateway-spec-restapi/my-api/Endpoint", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "CloudWatchRole": { + "id": "CloudWatchRole", + "path": "test-apigateway-spec-restapi/my-api/CloudWatchRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/CloudWatchRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Account": { + "id": "Account", + "path": "test-apigateway-spec-restapi/my-api/Account", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Account", + "aws:cdk:cloudformation:props": { + "cloudWatchRoleArn": { + "Fn::GetAtt": [ + "myapiCloudWatchRole095452E5", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnAccount", + "version": "0.0.0" + } + }, + "ApiKey": { + "id": "ApiKey", + "path": "test-apigateway-spec-restapi/my-api/ApiKey", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/ApiKey/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::ApiKey", + "aws:cdk:cloudformation:props": { + "enabled": true, + "stageKeys": [ + { + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "stageName": { + "Ref": "myapiDeploymentStagebeta96434BEB" + } + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnApiKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.ApiKey", + "version": "0.0.0" + } + }, + "UsagePlan": { + "id": "UsagePlan", + "path": "test-apigateway-spec-restapi/my-api/UsagePlan", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/my-api/UsagePlan/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::UsagePlan", + "aws:cdk:cloudformation:props": { + "apiStages": [ + { + "apiId": { + "Ref": "myapi4C7BF186" + }, + "stage": { + "Ref": "myapiDeploymentStagebeta96434BEB" + }, + "throttle": { + "/v1/toys/GET": { + "burstLimit": 2, + "rateLimit": 10 + } + } + } + ], + "description": "Free tier monthly usage plan", + "quota": { + "limit": 10000, + "period": "MONTH" + }, + "throttle": { + "rateLimit": 5 + }, + "usagePlanName": "Basic" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnUsagePlan", + "version": "0.0.0" + } + }, + "UsagePlanKeyResource:testapigatewayspecrestapimyapiApiKey950FF760": { + "id": "UsagePlanKeyResource:testapigatewayspecrestapimyapiApiKey950FF760", + "path": "test-apigateway-spec-restapi/my-api/UsagePlan/UsagePlanKeyResource:testapigatewayspecrestapimyapiApiKey950FF760", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::UsagePlanKey", + "aws:cdk:cloudformation:props": { + "keyId": { + "Ref": "myapiApiKey43446CCF" + }, + "keyType": "API_KEY", + "usagePlanId": { + "Ref": "myapiUsagePlan56F9C4F2" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.CfnUsagePlanKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.UsagePlan", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-apigateway.SpecRestApi", + "version": "0.0.0" + } + }, + "MyHandler": { + "id": "MyHandler", + "path": "test-apigateway-spec-restapi/MyHandler", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-apigateway-spec-restapi/MyHandler/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/MyHandler/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-spec-restapi/MyHandler/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "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 }" + }, + "role": { + "Fn::GetAtt": [ + "MyHandlerServiceRoleFFA06653", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "apigateway-spec-restapi": { + "id": "apigateway-spec-restapi", + "path": "apigateway-spec-restapi", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "apigateway-spec-restapi/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "apigateway-spec-restapi/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.102" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "apigateway-spec-restapi/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file