1

I'm creating a LambdaRestApi as follows

        this.gateway = new apigw.LambdaRestApi(this, "Endpoint", {
            handler: hello,
            endpointExportName: "MainURL"
        })

and I'd like to get to the CfnOutput it generates, is it possible? I want to pass it to other functions and I want to avoid creating a new one.

Specifically the situation I'm tackling is this: I have have a post stage that verifies things are working at it uses the CfnOutput:

deployStage.addPost(
    new CodeBuildStep("VerifyAPIGatewayEndpoint", {
        envFromCfnOutputs: {
            ENDPOINT_URL: deploy.hcEndpoint
        },
        commands: [
            "curl -Ssf $ENDPOINT_URL",
            "curl -Ssf $ENDPOINT_URL/hello",
            "curl -Ssf $ENDPOINT_URL/test"
        ]
    })
)

That deploy.hcEndpoint is a CfnOutput that I'm manually creating after the LambdaRestApi is created:

const gateway = new LambdaRestApi(this, "Endpoint", {handler: hello})
this.hcEndpoint = new CfnOutput(this, "GatewayUrl", {value: gateway.url})

and then making sure that every construct makes it available to its parent.

Using CfnOutputs in the post-deployment step makes sense. I am trying to learn the proper way of doing things, and also have clean stacks. With only one Lambda function it's no big deal, but with tens or hundreds it might. And since LambdaRestApi already creates the output, it does feel like I'm repeating myself by creating an identical one.

Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622

2 Answers2

3

Assuming you are using the following code for your LambdaRestApi:

this.gateway = new apigw.LambdaRestApi(this, "Endpoint", {
    handler: hello,
    endpointExportName: "MainURL"
});

Referencing in same stack as LambdaRestApi

const outputValue = this.gateway.urlForPath("/");

Looking at the source code, the output value is just a call to urlForPath. The method is public, so you can use it directly.

Referencing from another stack

You can use cross stack references to get a reference to the output value of the stack.

import { Fn } from 'aws-cdk-lib';
const outputValue = Fn.importValue("MainURL");

If you try to use the first method in another stack, CDK will just generate a cross stack reference dynamically by adding extra outputs, so it is better to import the value directly.

Kaustubh Khavnekar
  • 2,553
  • 2
  • 14
  • Thank you for the answer. Instead of `importValue`, I could just make `gateway.url` accessible but the parent construct, but at some point, I have to re-package it in a `CfnOutput` because that's what `CodeBuildStep` expects. Since `LambdaRestApi` already does it for me, it felt odd to do it again. I updated the question with those details. – Pablo Fernandez Jan 30 '22 at 12:24
  • @pupeno If you need a direct reference to the `CfnOutput` in `CodeBuildStep`, you can use the escape hatch approach suggested by @fedonev – Kaustubh Khavnekar Jan 30 '22 at 13:06
3

I'd like to get to the CfnOutput it generates, is it possible?

Yes. Use the escape hatch syntax to get a reference to the CfnOutput that RestApi creates for the endpointExportName:

const urlCfnOutput = this.gateway.node.findChild('Endpoint') as cdk.CfnOutput;

console.log(urlCfnOutput.exportName);
// MainURL

console.log(urlCfnOutput.value);
// https://${Token[TOKEN.258]}.execute-api.us-east-1.${Token[AWS.URLSuffix.3]}/${Token[TOKEN.277]}/

Prefer standard CDK

As their name suggests, "escape hatches" are for "emergencies" when the CDK's standard solutions fail. Your use case may be one such instance, I don't know. But as @Kaustubh Khavnekar points out, you don't need the CfnOutput to get the url token value.

console.log(this.gateway.url)
// https://${Token[TOKEN.258]}.execute-api.us-east-1.${Token[AWS.URLSuffix.3]}/${Token[TOKEN.277]}/
fedonev
  • 20,327
  • 2
  • 25
  • 34