0

Its a pretty common pattern when using API GW openapi to reference logical ids from the same stack to create a template where items are substituted. While some consider it a bit hacky it works well in my opinion for being able to leverage 1 stop development and deployments with openapi. Reference to this is at AWS CDK how to create an API Gateway backed by Lambda from OpenApi spec?.

Looking for best practices as if there is a way to reference an item in another stack when creating the openapi template.

Stack 1 (a shared s3 bucket) Stack 2 take in param to s3 as shown below (which generates an export in the cloud formation templates)

interface Stack2Props extends CommonStackProps {
    bucket_1: aws_s3.Bucket
}

export class Stack2 extends Stack {


    constructor(scope: Construct, id: string, props: Stack2Props) {
        super(scope, id, props);
....
}

The best i could figure to do was in the stack 1 to export a well known from stack 1 variable then reference it in stack2 in the template:

        // export for cross-stack reference in the template
        new CfnOutput(this, 'BucketRef', {
            value: bucket.bucketName,
            description: 'The bucket name of the bucket',
            exportName: 'MyBucket',
        });

        uri:
          Fn::Sub:
            - 'arn:aws:apigateway:us-east-1:s3:path/${MyBucket}/{path}'
            - MyBucket:
                Fn::ImportValue: MyBucket

Don't know if there is a better way here to do this.

user2403018
  • 297
  • 1
  • 4
  • 12

1 Answers1

0

Since you are using AWS CDK - a library for a high-level language you can avoid using CloudFormation methods like Fn::Sub and replace the values in your case in Typescript by passing a dictionary to something like a brackets parser

Here is a simple standalone solution

private compileOpenApi(apiDefinition: string, dictionary: { [key: string]: string }): string {
        let compiledDefinition = apiDefinition;

        Object.entries(dictionary).forEach(([key, value]) => {
            compiledDefinition = compiledDefinition.replace(new RegExp(key, 'g'), value);
        });

        return compiledDefinition;
    }

And pass the values you want to replace like

new apigateway.SpecRestApi(
    this, `MySpecRestApi`, {
        apiDefinition: apigateway.ApiDefinition.fromInline(
            JSON.parse(this.compileOpenApi(fs.readFileSync(props.openApiFilePath).toString(), {
                '{{MyBucketArn}}': props.myBucketArn,
                '{{MyBucketPath}}': props.myBucketPath,
        }))),
    }
Stoyan Georgiev
  • 345
  • 2
  • 8