From 0a6153375a641de6c49592b925d9595701309f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B9=E3=82=8A=E3=82=93=E3=81=90?= <70102274+lawofcycles@users.noreply.github.com> Date: Fri, 20 Oct 2023 00:25:59 +0000 Subject: [PATCH] fix(api-gateway): Error: Resource's path part only allow [a-zA-Z0-9:._-], an optional trailing '+'(module name) --- .../integ.restapi.js.snapshot/manifest.json | 41 ++++++++++++++++--- .../test-apigateway-restapi.assets.json | 4 +- .../test-apigateway-restapi.template.json | 18 ++++---- .../test/integ.restapi.js.snapshot/tree.json | 18 ++++---- .../test/aws-apigateway/test/integ.restapi.ts | 2 +- .../aws-apigateway/lib/resource.ts | 4 +- .../aws-apigateway/test/resource.test.ts | 17 ++++++++ 7 files changed, 75 insertions(+), 29 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/manifest.json index 45e72a2553f53..8bf532b3ad1a7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/manifest.json @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "test-apigateway-restapi.template.json", + "terminationProtection": false, "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}/56bfbd024f208cd5c005d4ddbdea5b0a1e3ba63af4733cc26b91cf871e227138.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/7730a7574bd54d8b8cc5ce3a8fc74a2b2cec7fa63897f605899d3a225bd67bda.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -54,7 +55,7 @@ "/test-apigateway-restapi/my-api/Deployment/Resource": [ { "type": "aws:cdk:logicalId", - "data": "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6" + "data": "myapiDeployment92F2CB49069d16df09c59427069eb74581a0403d" } ], "/test-apigateway-restapi/my-api/DeploymentStage.beta/Resource": [ @@ -111,16 +112,16 @@ "data": "myapiv1toysPUT59AFBBC2" } ], - "/test-apigateway-restapi/my-api/Default/v1/appliances:all/Resource": [ + "/test-apigateway-restapi/my-api/Default/v1/$appliances:all/Resource": [ { "type": "aws:cdk:logicalId", - "data": "myapiv1appliancesallCF8C6A16" + "data": "myapiv1appliancesallD279897B" } ], - "/test-apigateway-restapi/my-api/Default/v1/appliances:all/GET/Resource": [ + "/test-apigateway-restapi/my-api/Default/v1/$appliances:all/GET/Resource": [ { "type": "aws:cdk:logicalId", - "data": "myapiv1appliancesallGETC4DF552D" + "data": "myapiv1appliancesallGETB8EB1B77" } ], "/test-apigateway-restapi/my-api/Default/v1/books/Resource": [ @@ -224,6 +225,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "myapiv1appliancesallCF8C6A16": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1appliancesallCF8C6A16", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "myapiv1appliancesallGETC4DF552D": [ + { + "type": "aws:cdk:logicalId", + "data": "myapiv1appliancesallGETC4DF552D", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "test-apigateway-restapi" @@ -241,6 +269,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "apigatewayrestapiDefaultTestDeployAssert6A9696A7.template.json", + "terminationProtection": false, "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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.assets.json index 700064fe33129..3efe69ea00eec 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.assets.json @@ -1,7 +1,7 @@ { "version": "34.0.0", "files": { - "56bfbd024f208cd5c005d4ddbdea5b0a1e3ba63af4733cc26b91cf871e227138": { + "7730a7574bd54d8b8cc5ce3a8fc74a2b2cec7fa63897f605899d3a225bd67bda": { "source": { "path": "test-apigateway-restapi.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "56bfbd024f208cd5c005d4ddbdea5b0a1e3ba63af4733cc26b91cf871e227138.json", + "objectKey": "7730a7574bd54d8b8cc5ce3a8fc74a2b2cec7fa63897f605899d3a225bd67bda.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.template.json index 6b9facbb24b22..4da24fb620a2d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/test-apigateway-restapi.template.json @@ -57,7 +57,7 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6": { + "myapiDeployment92F2CB49069d16df09c59427069eb74581a0403d": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "Description": "beta stage", @@ -66,8 +66,8 @@ } }, "DependsOn": [ - "myapiv1appliancesallGETC4DF552D", - "myapiv1appliancesallCF8C6A16", + "myapiv1appliancesallGETB8EB1B77", + "myapiv1appliancesallD279897B", "myapiv1booksGETC6B996D0", "myapiv1booksPOST53E2832E", "myapiv1books1D4BE6C1", @@ -86,7 +86,7 @@ "CacheClusterEnabled": true, "CacheClusterSize": "0.5", "DeploymentId": { - "Ref": "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6" + "Ref": "myapiDeployment92F2CB49069d16df09c59427069eb74581a0403d" }, "Description": "beta stage", "MethodSettings": [ @@ -290,19 +290,19 @@ } } }, - "myapiv1appliancesallCF8C6A16": { + "myapiv1appliancesallD279897B": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Ref": "myapiv113487378" }, - "PathPart": "appliances:all", + "PathPart": "$appliances:all", "RestApiId": { "Ref": "myapi4C7BF186" } } }, - "myapiv1appliancesallGETC4DF552D": { + "myapiv1appliancesallGETB8EB1B77": { "Type": "AWS::ApiGateway::Method", "Properties": { "AuthorizationType": "NONE", @@ -311,7 +311,7 @@ "Type": "MOCK" }, "ResourceId": { - "Ref": "myapiv1appliancesallCF8C6A16" + "Ref": "myapiv1appliancesallD279897B" }, "RestApiId": { "Ref": "myapi4C7BF186" @@ -682,7 +682,7 @@ } }, "DependsOn": [ - "myapiv1appliancesallGETC4DF552D", + "myapiv1appliancesallGETB8EB1B77", "myapiv1booksGETC6B996D0", "myapiv1booksPOST53E2832E", "myapiv1toysGET7348114D", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/tree.json index 267ba76edc0c4..ff7900f722740 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.js.snapshot/tree.json @@ -144,7 +144,7 @@ "cacheClusterEnabled": true, "cacheClusterSize": "0.5", "deploymentId": { - "Ref": "myapiDeployment92F2CB4993c0f175ba8d5964f5e1cc7bc64fe6e6" + "Ref": "myapiDeployment92F2CB49069d16df09c59427069eb74581a0403d" }, "description": "beta stage", "methodSettings": [ @@ -468,20 +468,20 @@ "version": "0.0.0" } }, - "appliances:all": { - "id": "appliances:all", - "path": "test-apigateway-restapi/my-api/Default/v1/appliances:all", + "$appliances:all": { + "id": "$appliances:all", + "path": "test-apigateway-restapi/my-api/Default/v1/$appliances:all", "children": { "Resource": { "id": "Resource", - "path": "test-apigateway-restapi/my-api/Default/v1/appliances:all/Resource", + "path": "test-apigateway-restapi/my-api/Default/v1/$appliances:all/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", "aws:cdk:cloudformation:props": { "parentId": { "Ref": "myapiv113487378" }, - "pathPart": "appliances:all", + "pathPart": "$appliances:all", "restApiId": { "Ref": "myapi4C7BF186" } @@ -494,11 +494,11 @@ }, "GET": { "id": "GET", - "path": "test-apigateway-restapi/my-api/Default/v1/appliances:all/GET", + "path": "test-apigateway-restapi/my-api/Default/v1/$appliances:all/GET", "children": { "Resource": { "id": "Resource", - "path": "test-apigateway-restapi/my-api/Default/v1/appliances:all/GET/Resource", + "path": "test-apigateway-restapi/my-api/Default/v1/$appliances:all/GET/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", "aws:cdk:cloudformation:props": { @@ -508,7 +508,7 @@ "type": "MOCK" }, "resourceId": { - "Ref": "myapiv1appliancesallCF8C6A16" + "Ref": "myapiv1appliancesallD279897B" }, "restApiId": { "Ref": "myapi4C7BF186" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.ts index 77c3b1b2e5ea5..c255f1c64d75a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.ts @@ -43,7 +43,7 @@ class Test extends cdk.Stack { toys.addMethod('POST'); toys.addMethod('PUT'); - const appliances = v1.addResource('appliances:all'); + const appliances = v1.addResource('$appliances:all'); appliances.addMethod('GET'); const books = v1.addResource('books'); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts b/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts index 562764ef23bcf..16f6af41840ba 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts @@ -561,8 +561,8 @@ function validateResourcePathPart(part: string) { } } - if (!/^[a-zA-Z0-9:\.\_\-]+$/.test(part)) { - throw new Error(`Resource's path part only allow [a-zA-Z0-9:._-], an optional trailing '+' + if (!/^[a-zA-Z0-9:\.\_\-\$]+$/.test(part)) { + throw new Error(`Resource's path part only allow [a-zA-Z0-9:._-$], an optional trailing '+' and curly braces at the beginning and the end: ${part}`); } } diff --git a/packages/aws-cdk-lib/aws-apigateway/test/resource.test.ts b/packages/aws-cdk-lib/aws-apigateway/test/resource.test.ts index 2860f67252c22..0ea6a01caa4e0 100644 --- a/packages/aws-cdk-lib/aws-apigateway/test/resource.test.ts +++ b/packages/aws-cdk-lib/aws-apigateway/test/resource.test.ts @@ -197,6 +197,7 @@ describe('resource', () => { const aResource = api.root.addResource('a'); const cResource = aResource.addResource('b').addResource('c'); const colonResource = cResource.addResource('d:e'); + const dollarResource = cResource.addResource('$d'); // THEN expect(stack.resolve(api.urlForPath(aResource.path))).toEqual({ @@ -247,6 +248,22 @@ describe('resource', () => { ], ], }); + expect(stack.resolve(api.urlForPath(dollarResource.path))).toEqual({ + 'Fn::Join': [ + '', + [ + 'https://', + { Ref: 'apiC8550315' }, + '.execute-api.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { Ref: 'apiDeploymentStageprod896C8101' }, + '/a/b/c/$d', + ], + ], + }); });