1

I have created this stack:

    export class InfrastructureStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);


    const bucket = new s3.Bucket(this, "My Hello Website", {
      websiteIndexDocument: 'index.html',
      websiteErrorDocument: 'error.html',
      publicReadAccess: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });

    const api = new apigateway.RestApi(this, "My Endpoint", {
      restApiName: "My rest API name",
      description: "Some cool description"
    });

    const myLambda = new lambda.Function(this, 'My Backend', {
      runtime: lambda.Runtime.NODEJS_8_10,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, 'code'))
    });

    const apiToLambda = new apigateway.LambdaIntegration(myLambda)

    api.root.addMethod('GET', apiToLambda);

    updateWebsiteUrl.newUrl(api.url);
    }
    }

Last line of code is my function to update asset that will be deployed on S3 as a website with a API url that will be created during deployment. This is just a plain Node.js script that replaces files PLACEHOLDER with api.url.
Of course during compile time the CDK does not know what will be the final adress of REST endpoint because this is happening during deploy time and it updates my url with somethis like:
'https://${Token[TOKEN.26]}.execute-api.${Token[AWS::Region.4]}.${Token[AWS::URLSuffix.1]}/${Token[TOKEN.32]}/;'

Is there any way that I can update this after integrating lambda with API endpooint after deploying those?

I would like to use @aws-cdk/aws-s3-deployment module to deploy code to newly created bucket. All in the same Stack, so one cdk deploy will update everything I need.

To avoid confusion. My updateWebsiteUrl is:

    export function newUrl(newUrl: string): void {

    const scriptPath = path.join(__dirname, '/../../front/');
    const scriptName = 'script.js';

    fs.readFile(scriptPath + scriptName, (err, buf) => {
        let scriptContent : string = buf.toString();

        let newScript = scriptContent.replace('URL_PLACEHOLDER', newUrl);

        fs.writeFile(scriptPath + 'newScript.js', newScript, () => {
            console.log('done writing');
        });
    });
  }

And my script is just simple:

const url = URL_PLACEHOLDER;

function foo() {
    let req = new XMLHttpRequest();
    req.open('GET', url , false);

    req.send(null);

    if (req.status == 200) {
        replaceContent(req.response);
    }
}

function replaceContent(content) {
    document.getElementById('content').innerHTML = content;
}
Zychoo
  • 625
  • 2
  • 8
  • 25
  • is there any reason you do not use aws-s3-deployment in the first case (instaead of updateWebsiteUrl) ? – quadroid Nov 25 '19 at 13:29
  • I want to update my static website with API endpoint url and then deploy it. I need to replace some of my code. – Zychoo Nov 25 '19 at 15:18

1 Answers1

0

I ran into the same issue today and managed to find a solution for it.

The C# code I am using in my CDK program is the following:

// This will at runtime be just a token which refers to the actual JSON in the format  {'api':{'baseUrl':'https://your-url'}}
var configJson = stack.ToJsonString(new Dictionary<string, object>
        {
            ["api"] = new Dictionary<string, object>
            {
                ["baseUrl"] = api.Url
            }
        });

var configFile = new AwsCustomResource(this, "config-file", new AwsCustomResourceProps
        {
            OnUpdate = new AwsSdkCall
            {
                Service = "S3",
                Action = "putObject",
                Parameters = new Dictionary<string, string>
                {
                    ["Bucket"] = bucket.BucketName,
                    ["Key"] = "config.json",
                    ["Body"] = configJson,
                    ["ContentType"] = "application /json",
                    ["CacheControl"] = "max -age=0, no-cache, no-store, must-revalidate"
                },
                PhysicalResourceId = PhysicalResourceId.Of("config"),
            },
            Policy = AwsCustomResourcePolicy.FromStatements(
                new[]
                {
                    new PolicyStatement(new PolicyStatementProps
                    {
                        Actions = new[] { "s3:PutObject" },
                        Resources= new [] { bucket.ArnForObjects("config.json") }
                    })
                })
        });
    }

You will need to install the following package to have the types available: https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html

It is basically a part of the solution you can find as an answer to this question AWS CDK passing API Gateway URL to static site in same Stack, or at this GitHub repository: https://github.com/jogold/cloudstructs/blob/master/src/static-website/index.ts#L134

Schweder
  • 1,464
  • 2
  • 13
  • 19