diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integ.json new file mode 100644 index 0000000000000..cb8e28c865d4e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "specrestapi-import-deployment-stage/DefaultTest": { + "stacks": [ + "integtest-specrestapi-import-deployment-stage" + ], + "assertionStack": "specrestapi-import-deployment-stage/DefaultTest/DeployAssert", + "assertionStackName": "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.assets.json new file mode 100644 index 0000000000000..758197d57fc76 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "963d95f2b946c101b476b2c2b3faa935244354f27c8cef2c0d0a8215cc5f816b": { + "source": { + "path": "integtest-specrestapi-import-deployment-stage.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "963d95f2b946c101b476b2c2b3faa935244354f27c8cef2c0d0a8215cc5f816b.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-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.template.json new file mode 100644 index 0000000000000..39f11c55ecd7c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/integtest-specrestapi-import-deployment-stage.template.json @@ -0,0 +1,100 @@ +{ + "Resources": { + "myapi4C7BF186": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "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" + } + } + } + }, + "Name": "my-api" + } + }, + "MyManualDeployment92F2175C1dcdcb8f1c24d86b6090e78df1fafcd3": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "StageName": "myStage" + } + } + }, + "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-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/manifest.json new file mode 100644 index 0000000000000..2159288d8af91 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/manifest.json @@ -0,0 +1,119 @@ +{ + "version": "36.0.0", + "artifacts": { + "integtest-specrestapi-import-deployment-stage.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtest-specrestapi-import-deployment-stage.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtest-specrestapi-import-deployment-stage": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtest-specrestapi-import-deployment-stage.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}/963d95f2b946c101b476b2c2b3faa935244354f27c8cef2c0d0a8215cc5f816b.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtest-specrestapi-import-deployment-stage.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": [ + "integtest-specrestapi-import-deployment-stage.assets" + ], + "metadata": { + "/integtest-specrestapi-import-deployment-stage/my-api/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myapi4C7BF186" + } + ], + "/integtest-specrestapi-import-deployment-stage/MyManualDeployment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyManualDeployment92F2175C1dcdcb8f1c24d86b6090e78df1fafcd3" + } + ], + "/integtest-specrestapi-import-deployment-stage/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integtest-specrestapi-import-deployment-stage/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integtest-specrestapi-import-deployment-stage" + }, + "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.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}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.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": [ + "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets" + ], + "metadata": { + "/specrestapi-import-deployment-stage/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/specrestapi-import-deployment-stage/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "specrestapi-import-deployment-stage/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets.json new file mode 100644 index 0000000000000..66b1d8fe0cbf8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.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-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/specrestapiimportdeploymentstageDefaultTestDeployAssert410B3AFA.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-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/tree.json new file mode 100644 index 0000000000000..32f9eed0afe35 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.js.snapshot/tree.json @@ -0,0 +1,207 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integtest-specrestapi-import-deployment-stage": { + "id": "integtest-specrestapi-import-deployment-stage", + "path": "integtest-specrestapi-import-deployment-stage", + "children": { + "my-api": { + "id": "my-api", + "path": "integtest-specrestapi-import-deployment-stage/my-api", + "children": { + "Resource": { + "id": "Resource", + "path": "integtest-specrestapi-import-deployment-stage/my-api/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::RestApi", + "aws:cdk:cloudformation:props": { + "body": { + "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" + } + } + } + }, + "name": "my-api" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnRestApi", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "integtest-specrestapi-import-deployment-stage/my-api/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.ResourceBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.SpecRestApi", + "version": "0.0.0" + } + }, + "MyManualDeployment": { + "id": "MyManualDeployment", + "path": "integtest-specrestapi-import-deployment-stage/MyManualDeployment", + "children": { + "Resource": { + "id": "Resource", + "path": "integtest-specrestapi-import-deployment-stage/MyManualDeployment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Deployment", + "aws:cdk:cloudformation:props": { + "restApiId": { + "Ref": "myapi4C7BF186" + }, + "stageName": "myStage" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnDeployment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Deployment", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integtest-specrestapi-import-deployment-stage/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integtest-specrestapi-import-deployment-stage/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "specrestapi-import-deployment-stage": { + "id": "specrestapi-import-deployment-stage", + "path": "specrestapi-import-deployment-stage", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "specrestapi-import-deployment-stage/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "specrestapi-import-deployment-stage/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "specrestapi-import-deployment-stage/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "specrestapi-import-deployment-stage/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "specrestapi-import-deployment-stage/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.ts new file mode 100644 index 0000000000000..c465064381eae --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.spec-restapi.import-deploymentstage.ts @@ -0,0 +1,74 @@ +import * as cdk from 'aws-cdk-lib/core'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; +import * as integ from '@aws-cdk/integ-tests-alpha'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integtest-specrestapi-import-deployment-stage'); + +const apiDefinition = { + 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', + }, + }, + }, +}; + +// Set deploy to false so SpecRestApi does not automatically create a Deployment +const api = new apigateway.SpecRestApi(stack, 'my-api', { + deploy: false, + apiDefinition: apigateway.ApiDefinition.fromInline(apiDefinition), +}); + +// Manually create a deployment that deploys to an existing stage +const deployment = new apigateway.Deployment(stack, 'MyManualDeployment', { + api: api, + stageName: 'myStage', +}); + +deployment.addToLogicalId(apiDefinition); + +new integ.IntegTest(app, 'specrestapi-import-deployment-stage', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-apigateway/README.md b/packages/aws-cdk-lib/aws-apigateway/README.md index 136e9a59bc388..9d97646885e5b 100644 --- a/packages/aws-cdk-lib/aws-apigateway/README.md +++ b/packages/aws-cdk-lib/aws-apigateway/README.md @@ -270,7 +270,7 @@ The following example uses sets up two Resources '/pets' and '/books' in separat > **Warning:** In the code above, an API Gateway deployment is created during the initial CDK deployment. However, if there are changes to the resources in subsequent CDK deployments, a new API Gateway deployment is not automatically created. As a result, the latest state of the resources is not reflected. To ensure the latest state -of the resources is reflected, a manual deployment of the API Gateway is required after the CDK deployment. +of the resources is reflected, a manual deployment of the API Gateway is required after the CDK deployment. See [Controlled triggering of deployments](#controlled-triggering-of-deployments) for more info. ## Integration Targets @@ -941,7 +941,7 @@ Instructions for configuring your trust store can be found [here](https://aws.am By default, the `RestApi` construct will automatically create an API Gateway [Deployment] and a "prod" [Stage] which represent the API configuration you defined in your CDK app. This means that when you deploy your app, your API will -be have open access from the internet via the stage URL. +have open access from the internet via the stage URL. The URL of your API can be obtained from the attribute `restApi.url`, and is also exported as an `Output` from your stack, so it's printed when you `cdk @@ -1000,6 +1000,67 @@ const api = new apigateway.RestApi(this, 'books', { cloudWatchRoleRemovalPolicy: cdk.RemovalPolicy.DESTROY, }); ``` +### Deploying to an existing stage + +#### Using RestApi + +If you want to use an existing stage to deploy your `RestApi`, first set `{ deploy: false }` so the construct doesn't automatically create new `Deployment` and `Stage` resources. Then you can manually define a `apigateway.Deployment` resource and specify the stage name for your existing stage using the `stageName` property. + +Note that as long as the deployment's logical ID doesn't change, it will represent the snapshot in time when the resource was created. To ensure your deployment reflects changes to the `RestApi` model, see [Controlled triggering of deployments](#controlled-triggering-of-deployments). +```ts +const restApi = new apigateway.RestApi(this, 'my-rest-api', { + deploy: false, +}); + +// Use `stageName` to deploy to an existing stage +const deployment = new apigateway.Deployment(this, 'my-deployment', { + api: restApi, + stageName: 'dev', + retainDeployments: true, // keep old deployments +}); +``` +#### Using SpecRestApi +If you want to use an existing stage to deploy your `SpecRestApi`, first set `{ deploy: false }` so the construct doesn't automatically create new `Deployment` and `Stage` resources. Then you can manually define a `apigateway.Deployment` resource and specify the stage name for your existing stage using the `stageName` property. + +To automatically create a new deployment that reflects the latest API changes, you can use the `addToLogicalId()` method and pass in your OpenAPI definition. + +```ts +const myApiDefinition = apigateway.ApiDefinition.fromAsset('path-to-file.json'); +const specRestApi = new apigateway.SpecRestApi(this, 'my-specrest-api', { + deploy: false, + apiDefinition: myApiDefinition +}); + +// Use `stageName` to deploy to an existing stage +const deployment = new apigateway.Deployment(this, 'my-deployment', { + api: specRestApi, + stageName: 'dev', + retainDeployments: true, // keep old deployments +}); + +// Trigger a new deployment on OpenAPI definition updates +deployment.addToLogicalId(myApiDefinition); + +``` + +> Note: If the `stageName` property is set but a stage with the corresponding name does not exist, a new stage resource will be created with the provided stage name. + +> Note: If you update the `stageName` property, you should be triggering a new deployment (i.e. with an updated logical ID and API changes). Otherwise, an error will occur during deployment. + +### Controlled triggering of deployments + +By default, the `RestApi` construct deploys changes immediately. If you want to +control when deployments happen, set `{ deploy: false }` and create a `Deployment` construct yourself. Add a revision counter to the construct ID, and update it in your source code whenever you want to trigger a new deployment: +```ts +const restApi = new apigateway.RestApi(this, 'my-api', { + deploy: false, +}); + +const deploymentRevision = 5; // Bump this counter to trigger a new deployment +new apigateway.Deployment(this, `Deployment${deploymentRevision}`, { + api: restApi +}); +``` ### Deep dive: Invalidation of deployments diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts index 3b70432798446..c245f82769110 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts @@ -26,6 +26,15 @@ export interface DeploymentProps { * @default false */ readonly retainDeployments?: boolean; + + /** + * The name of the stage the API Gateway deployment deploys to. + * + * @default - No stage name. If the `stageName` property is set but a stage with the + * corresponding name does not exist, a new stage resource will be created with the + * provided stage name. + */ + readonly stageName?: string; } /** @@ -62,6 +71,10 @@ export class Deployment extends Resource { /** @attribute */ public readonly deploymentId: string; public readonly api: IRestApi; + /** + * The stage of the API gateway deployment. + */ + public readonly stageName?: string; private readonly resource: LatestDeploymentResource; @@ -71,6 +84,7 @@ export class Deployment extends Resource { this.resource = new LatestDeploymentResource(this, 'Resource', { description: props.description, restApi: props.api, + stageName: props.stageName, }); if (props.retainDeployments) { @@ -126,6 +140,7 @@ export class Deployment extends Resource { interface LatestDeploymentResourceProps { readonly description?: string; readonly restApi: IRestApi; + readonly stageName?: string; } class LatestDeploymentResource extends CfnDeployment { @@ -137,6 +152,7 @@ class LatestDeploymentResource extends CfnDeployment { super(scope, id, { description: props.description, restApiId: props.restApi.restApiId, + stageName: props.stageName, }); this.api = props.restApi; diff --git a/packages/aws-cdk-lib/aws-apigateway/test/deployment.test.ts b/packages/aws-cdk-lib/aws-apigateway/test/deployment.test.ts index 667634408b1b2..5495d40f64361 100644 --- a/packages/aws-cdk-lib/aws-apigateway/test/deployment.test.ts +++ b/packages/aws-cdk-lib/aws-apigateway/test/deployment.test.ts @@ -126,6 +126,21 @@ describe('deployment', () => { }); }); + test('"stage" can be set on the deployment', () => { + // GIVEN + const stack = new Stack(); + const api = new apigateway.RestApi(stack, 'api', { deploy: false, cloudWatchRole: false }); + api.root.addMethod('GET'); + + // WHEN + new apigateway.Deployment(stack, 'deployment', { api, stageName: 'dev' }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Deployment', { + StageName: 'dev', + }); + }); + describe('logical ID of the deployment resource is salted', () => { test('before salting', () => { // GIVEN