'AWS CDK | Create a REST API spanning multiple CDK Stacks
We are using AWS CDK to create our Serverless REST API. However, there are a large number of endpoints and sometimes we have to destroy and redeploy our stack. To prevent the REST API URL from changing with each deployment, I am planning to create the API GATEWAY in one stack and add methods and resources in a separate stack. How can I refer the created rest API in a separate stack?
Tried to implement something from https://github.com/aws/aws-cdk/issues/3705, but all of the resources(API Gateway, resource and methods) are being pushed in a single stack instead of API Gateway in one stack and the resources in other stack.
Relevant codes snippets are provided below:
bts-app-cdk.ts
const first = new FirstStack(app, 'FirstStack', {
env: {
region: 'us-east-1',
account: '1234567890',
}
});
const second = new SecondStack(app, 'SecondStack', {
apiGateway: first.apiGateway,
env: {
region: 'us-east-1',
account: '1234567890',
}
});
second.addDependency(first)
first-stack.ts
export class FirstStack extends cdk.Stack {
public readonly apiGateway: apig.IResource;
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const apiGateway = new apig.RestApi(this, 'BooksAPI', {
restApiName:'Books API',
})
apiGateway.root.addMethod('GET');
this.apiGateway = apiGateway.root;
}
}
second-stack
export interface SecondStackProps extends cdk.StackProps {
readonly apiGateway: apig.IResource;
}
export class SecondStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props: SecondStackProps) {
super(scope, id, props);
props.apiGateway.addMethod('ANY')
}
}
Solution 1:[1]
Seems that there is no way at the moment except using Cfn constructs, here's the github issue to track https://github.com/aws/aws-cdk/issues/1477
Solution 2:[2]
You have to set the deploy
prop to false
when instantiating your api-gw
.
Then you can pass the restApiId
and rootResourceId
as enviroment variables to stacks.
Finally you can use a Deployment
to deploy everything.
interface ResourceNestedStackProps extends NestedStackProps {
readonly restApiId: string;
readonly rootResourceId: string;
}
export class FirstStack extends cdk.Stack {
public readonly methods: Method[];
constructor(scope: cdk.Construct, props: ResourceNestedStackProps) {
super(scope, 'first-stack', props);
// get a hold of the rest api from attributes
const api = RestApi.fromRestApiAttributes(this, 'RestApi', {
restApiId: props.restApiId,
rootResourceId: props.rootResourceId,
})
// REPEAT THIS FOR METHODS
const method = api.root.addMethod('GET');
this.methods.push(method)
// ---
}
}
Then in the root stack file,
class RootStack extends Stack {
constructor(scope: Construct) {
const restApi = new RestApi(this, 'RestApi', {
deploy: false,
});
restApi.root.addMethod('ANY');
const firstStack = new FirstStack(this, {
restApiId: restApi.restApiId,
rootResourceId: restApi.restApiRootResourceId,
});
new DeployStack(this, {
restApiId: restApi.restApiId,
methods: [...firstStack.methods],
})
}
}
The deploy stack is where you deploy your API:
interface DeployStackProps extends NestedStackProps {
readonly restApiId: string;
readonly methods?: Method[];
}
class DeployStack extends NestedStack {
constructor(scope: Construct, props: DeployStackProps) {
super(scope, 'deploy-stack', props);
const deployment = new Deployment(this, 'Deployment', {
api: RestApi.fromRestApiId(this, 'RestApi', props.restApiId),
});
if (props.methods) {
for (const method of props.methods) {
deployment.node.addDependency(method);
}
}
new Stage(this, 'Stage', { deployment });
}
}
Refer this for more details: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.NestedStack.html
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | gafi |
Solution 2 | Akshay Kumar |