From 5fa391669ae50a91a50a16959bd9ff102829de5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=9A=80=20Jack?= Date: Wed, 1 Nov 2023 19:07:40 +1100 Subject: [PATCH] feat(infrastructure): add deploy:dev task to infrastructure projects for cdk hotswap deployment Adds a `deploy:dev` task to the infrastructure projects which perform a CDK hotswap deployment if possible in order to reduce dev cycle times. Given the dev cycle time reduction we consider this a better option than a local dev server, since local dev server requires managing credentials locally, as well as things like environment variables for pointing to other resources (eg ddb tables). Fixes #599 --- .../getting_started/shopping_list_app.md | 4 +- .../your_first_aws_pdk_project.md | 11 ++- .../developer_guides/infrastructure/index.md | 3 + .../src/components/infrastructure-commands.ts | 50 ++++++++++++ .../java/infrastructure-java-project.ts | 3 + .../python/infrastructure-py-project.ts | 3 + .../typescript/infrastructure-ts-project.ts | 3 + .../infrastructure-java-project.test.ts.snap | 61 ++++++++++++++ .../infrastructure-py-project.test.ts.snap | 61 ++++++++++++++ .../infrastructure-ts-project.test.ts.snap | 65 +++++++++++++++ .../developer_guides/type-safe-api/index.md | 79 ++++++++++--------- 11 files changed, 301 insertions(+), 42 deletions(-) create mode 100644 packages/infrastructure/src/components/infrastructure-commands.ts diff --git a/docs/content/getting_started/shopping_list_app.md b/docs/content/getting_started/shopping_list_app.md index 1d3600f44..e38dbd524 100644 --- a/docs/content/getting_started/shopping_list_app.md +++ b/docs/content/getting_started/shopping_list_app.md @@ -708,7 +708,7 @@ We are now ready to deploy our API. To do so, run the following steps: ```bash pdk build cd packages/infra -pdk run deploy --require-approval never +pdk deploy:dev ``` Once the deployment completes, we can test our API by navigating the the website (either via Cloudfront or locally) and trying out the API Explorer. @@ -1192,7 +1192,7 @@ If you are happy with your website locally, you can go ahead and deploy it to AW ```bash pdk build cd packages/infra -pdk run deploy --require-approval never +pdk deploy:dev ``` Once the deployment completes, navigate to your cloudfront URL to play around with your deployed website. diff --git a/docs/content/getting_started/your_first_aws_pdk_project.md b/docs/content/getting_started/your_first_aws_pdk_project.md index 3683b82d1..84f91ad5b 100644 --- a/docs/content/getting_started/your_first_aws_pdk_project.md +++ b/docs/content/getting_started/your_first_aws_pdk_project.md @@ -86,7 +86,7 @@ Inspecting the `projenrc` file, we notice that a single construct is instantiate - Any parameter listed here can be passed in via the `pdk new` command i.e: `--name="some-other-name"`. - For python, the moduleName defaults to a snake-cased project name. -You will also notice that the `synth()` method is called on this instance at the end of the file. When you run the `pdk` command, this file will be executed by your runtime and will synthesize this instance which will result in all the files that you see in the previous image. +You will also notice that the `synth()` method is called on this instance at the end of the file. When you run the `pdk` command, this file will be executed by your runtime and will synthesize this instance which will result in all the files that you see in the previous image. !!!info Whenever you change the `projenrc` file, make sure you run the `pdk` command from the root of your project to ensure your files are synthesized. @@ -293,7 +293,7 @@ For more details on these packages, refer to the [Type-Safe API Developer Guide] Now, lets build our API by running `pdk build` from the root of our monorepo. You will notice that each package in the monorepo is built in dependency order. !!!tip - If you run the `pdk build` command again without changing any files, you will notice that the build completes in a fraction of the time (1.7s as per below snippet) as it uses [cached results](https://nx.dev/concepts/how-caching-works) and will only re-build packages that have changed since the last time it was built. + If you run the `pdk build` command again without changing any files, you will notice that the build completes in a fraction of the time (1.7s as per below snippet) as it uses [cached results](https://nx.dev/concepts/how-caching-works) and will only re-build packages that have changed since the last time it was built. ```bash > NX Successfully ran target build for 7 projects @@ -738,9 +738,12 @@ We now can deploy our infrastructure by running the following command: ```bash cd packages/infra -pdk run deploy --require-approval never +pdk deploy:dev ``` +!!!note + The `pdk deploy:dev` command attempts a [CDK hotswap deployment](https://aws.amazon.com/blogs/developer/increasing-development-speed-with-cdk-watch/) if possible. In a production setting (for example in a ci/cd pipeline) use the `pdk deploy` command to ensure a full CloudFormation deployment is performed. + Once the deployment completes, you should see an output that resembles the following: @@ -756,7 +759,7 @@ In order to log in to your website, you first need to create a Cognito user. By 1. Navigate to the Cognito AWS console within the account you just deployed to. 1. Click on the user pool you just created 1. Click "Create user" -1. In invitation settings, select "Send an email invitation" +1. In invitation settings, select "Send an email invitation" 1. Enter a username 1. Enter an email address 1. In temporary password, select "Generate a password" diff --git a/packages/infrastructure/docs/developer_guides/infrastructure/index.md b/packages/infrastructure/docs/developer_guides/infrastructure/index.md index 4749da4eb..c70c9c56f 100644 --- a/packages/infrastructure/docs/developer_guides/infrastructure/index.md +++ b/packages/infrastructure/docs/developer_guides/infrastructure/index.md @@ -145,6 +145,9 @@ Congratulations! You have successfully deployed a website and api to AWS! To check out your website, navigate to the distribution link in the CDK deployment output above to view your website. +!!!tip + Use the `pdk deploy:dev` command in your infrastructure package to perform a CDK hotswap deployment for faster development iterations! + ## Destroying the deployed resources Now that you're done creating your first PDK project, destroy your deployed resources to avoid incurring any costs as follows: diff --git a/packages/infrastructure/src/components/infrastructure-commands.ts b/packages/infrastructure/src/components/infrastructure-commands.ts new file mode 100644 index 000000000..56d156efb --- /dev/null +++ b/packages/infrastructure/src/components/infrastructure-commands.ts @@ -0,0 +1,50 @@ +/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 */ +import { ProjectUtils } from "@aws/monorepo"; +import { Component, Project } from "projen"; + +/** + * Common commands for infrastructure projects + */ +export class InfrastructureCommands extends Component { + /** + * Retrieves an instance of InfrastructureCommands if one is associated to the given project + * @param project project instance + */ + static of(project: Project): InfrastructureCommands | undefined { + return project.components.find((c) => + ProjectUtils.isNamedInstanceOf(c, InfrastructureCommands) + ) as InfrastructureCommands | undefined; + } + + /** + * Retrieves an instance of InfrastructureCommands if one is associated to the given project, + * otherwise creates an InfrastructureCommands instance for the project. + * @param project project instance + */ + static ensure(project: Project): InfrastructureCommands { + return ( + InfrastructureCommands.of(project) || new InfrastructureCommands(project) + ); + } + + constructor(project: Project) { + super(project); + + // Add a development deployment task which uses hotswap for faster deployments + // See: https://aws.amazon.com/blogs/developer/increasing-development-speed-with-cdk-watch/ + const deployDevTask = project.addTask("deploy:dev", { + receiveArgs: true, + description: + "Performs a hotswap CDK deployment, useful for faster development cycles", + }); + // --hotswap-fallback falls back to a regular deployment if there are resources which have + // changed that cannot be hotswapped + deployDevTask.exec( + "cdk deploy --hotswap-fallback --require-approval never", + { + receiveArgs: true, + } + ); + } +} diff --git a/packages/infrastructure/src/projects/java/infrastructure-java-project.ts b/packages/infrastructure/src/projects/java/infrastructure-java-project.ts index 9f4989af8..07838979b 100644 --- a/packages/infrastructure/src/projects/java/infrastructure-java-project.ts +++ b/packages/infrastructure/src/projects/java/infrastructure-java-project.ts @@ -9,6 +9,7 @@ import * as Mustache from "mustache"; import { SampleFile } from "projen"; import { AwsCdkJavaApp } from "projen/lib/awscdk"; import { AwsCdkJavaAppOptions } from "./aws-cdk-java-app-options"; +import { InfrastructureCommands } from "../../components/infrastructure-commands"; import { DEFAULT_STACK_NAME } from "../../consts"; /** @@ -65,6 +66,8 @@ export class InfrastructureJavaProject extends AwsCdkJavaApp { }, }); + InfrastructureCommands.ensure(this); + this.pom.addPlugin("org.apache.maven.plugins/maven-surefire-plugin@3.1.2"); this.pom.addPlugin("org.apache.maven.plugins/maven-compiler-plugin@3.8.1", { configuration: { diff --git a/packages/infrastructure/src/projects/python/infrastructure-py-project.ts b/packages/infrastructure/src/projects/python/infrastructure-py-project.ts index 6b15e944c..eb8826a7b 100644 --- a/packages/infrastructure/src/projects/python/infrastructure-py-project.ts +++ b/packages/infrastructure/src/projects/python/infrastructure-py-project.ts @@ -9,6 +9,7 @@ import * as Mustache from "mustache"; import { SampleFile } from "projen"; import { AwsCdkPythonApp } from "projen/lib/awscdk"; import { AwsCdkPythonAppOptions } from "./aws-cdk-py-app-options"; +import { InfrastructureCommands } from "../../components/infrastructure-commands"; import { DEFAULT_STACK_NAME } from "../../consts"; /** @@ -66,6 +67,8 @@ export class InfrastructurePyProject extends AwsCdkPythonApp { }, }); + InfrastructureCommands.ensure(this); + ["pytest@^7", "syrupy@^4"].forEach((devDep) => this.addDevDependency(devDep) ); diff --git a/packages/infrastructure/src/projects/typescript/infrastructure-ts-project.ts b/packages/infrastructure/src/projects/typescript/infrastructure-ts-project.ts index 97496ebcf..5a02013a8 100644 --- a/packages/infrastructure/src/projects/typescript/infrastructure-ts-project.ts +++ b/packages/infrastructure/src/projects/typescript/infrastructure-ts-project.ts @@ -10,6 +10,7 @@ import { SampleFile } from "projen"; import { AwsCdkTypeScriptApp } from "projen/lib/awscdk"; import { NodeProject } from "projen/lib/javascript"; import { AwsCdkTypeScriptAppOptions } from "./aws-cdk-ts-app-options"; +import { InfrastructureCommands } from "../../components/infrastructure-commands"; import { DEFAULT_STACK_NAME } from "../../consts"; /** @@ -66,6 +67,8 @@ export class InfrastructureTsProject extends AwsCdkTypeScriptApp { }, }); + InfrastructureCommands.ensure(this); + this.addDeps("@aws/pdk"); const srcDir = path.resolve( diff --git a/packages/infrastructure/test/projects/java/__snapshots__/infrastructure-java-project.test.ts.snap b/packages/infrastructure/test/projects/java/__snapshots__/infrastructure-java-project.test.ts.snap index c50914a3c..44653b2af 100644 --- a/packages/infrastructure/test/projects/java/__snapshots__/infrastructure-java-project.test.ts.snap +++ b/packages/infrastructure/test/projects/java/__snapshots__/infrastructure-java-project.test.ts.snap @@ -316,6 +316,16 @@ dist/java }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -924,6 +934,16 @@ dist/java }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -1213,6 +1233,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -1697,6 +1724,16 @@ dist/java }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -1987,6 +2024,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -2515,6 +2559,16 @@ dist/java }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -2793,6 +2847,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { diff --git a/packages/infrastructure/test/projects/python/__snapshots__/infrastructure-py-project.test.ts.snap b/packages/infrastructure/test/projects/python/__snapshots__/infrastructure-py-project.test.ts.snap index 8df0b65fe..e3541f3a6 100644 --- a/packages/infrastructure/test/projects/python/__snapshots__/infrastructure-py-project.test.ts.snap +++ b/packages/infrastructure/test/projects/python/__snapshots__/infrastructure-py-project.test.ts.snap @@ -271,6 +271,16 @@ cython_debug/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -696,6 +706,16 @@ cython_debug/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -959,6 +979,13 @@ url = "https://test.pypi.org/legacy/" "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -1291,6 +1318,16 @@ cython_debug/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -1592,6 +1629,13 @@ url = "https://test.pypi.org/legacy/" "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -1919,6 +1963,16 @@ cython_debug/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -2165,6 +2219,13 @@ url = "https://test.pypi.org/legacy/" "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "npx projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { diff --git a/packages/infrastructure/test/projects/typescript/__snapshots__/infrastructure-ts-project.test.ts.snap b/packages/infrastructure/test/projects/typescript/__snapshots__/infrastructure-ts-project.test.ts.snap index ae54c5ea7..29085de46 100644 --- a/packages/infrastructure/test/projects/typescript/__snapshots__/infrastructure-ts-project.test.ts.snap +++ b/packages/infrastructure/test/projects/typescript/__snapshots__/infrastructure-ts-project.test.ts.snap @@ -684,6 +684,16 @@ cdk.out/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -1149,6 +1159,7 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "compile": "npx projen compile", "default": "npx projen default", "deploy": "npx projen deploy", + "deploy:dev": "npx projen deploy:dev", "destroy": "npx projen destroy", "diff": "npx projen diff", "eject": "npx projen eject", @@ -1708,6 +1719,16 @@ cdk.out/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -2161,6 +2182,7 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "compile": "npx projen compile", "default": "npx projen default", "deploy": "npx projen deploy", + "deploy:dev": "npx projen deploy:dev", "destroy": "npx projen destroy", "diff": "npx projen diff", "eslint": "npx projen eslint", @@ -2217,6 +2239,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -2937,6 +2966,16 @@ cdk.out/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -3391,6 +3430,7 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "compile": "npx projen compile", "default": "npx projen default", "deploy": "npx projen deploy", + "deploy:dev": "npx projen deploy:dev", "destroy": "npx projen destroy", "diff": "npx projen diff", "eslint": "npx projen eslint", @@ -3447,6 +3487,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { @@ -4221,6 +4268,16 @@ cdk.out/ }, ], }, + "deploy:dev": { + "description": "Performs a hotswap CDK deployment, useful for faster development cycles", + "name": "deploy:dev", + "steps": [ + { + "exec": "cdk deploy --hotswap-fallback --require-approval never", + "receiveArgs": true, + }, + ], + }, "destroy": { "description": "Destroys your cdk app in the AWS cloud", "name": "destroy", @@ -4674,6 +4731,7 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "compile": "npx projen compile", "default": "npx projen default", "deploy": "npx projen deploy", + "deploy:dev": "npx projen deploy:dev", "destroy": "npx projen destroy", "diff": "npx projen diff", "eslint": "npx projen eslint", @@ -4730,6 +4788,13 @@ Refer to [Developer Guide](https://aws.github.io/aws-pdk/developer_guides/infras "cwd": "infra", }, }, + "deploy:dev": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen deploy:dev", + "cwd": "infra", + }, + }, "destroy": { "executor": "nx:run-commands", "options": { diff --git a/packages/type-safe-api/docs/developer_guides/type-safe-api/index.md b/packages/type-safe-api/docs/developer_guides/type-safe-api/index.md index cd42685fd..85d5adb81 100644 --- a/packages/type-safe-api/docs/developer_guides/type-safe-api/index.md +++ b/packages/type-safe-api/docs/developer_guides/type-safe-api/index.md @@ -331,21 +331,21 @@ You can implement your lambda handlers in any of the supported languages, or mix Response, LoggingInterceptor, } from "myapi-typescript-runtime"; - + /** * Type-safe handler for the SayHello operation */ export const sayHello: SayHelloChainedHandlerFunction = async (request) => { LoggingInterceptor.getLogger(request).info("Start SayHello Operation"); - + // TODO: Implement SayHello Operation. `input` contains the request input. const { input } = request; - + return Response.internalFailure({ message: "Not Implemented!", }); }; - + /** * Entry point for the AWS Lambda handler for the SayHello operation. * The sayHelloHandler method wraps the type-safe handler and manages marshalling inputs and outputs @@ -356,10 +356,10 @@ You can implement your lambda handlers in any of the supported languages, or mix === "JAVA" In Java, you'll notice you have a lambda handler stub in `packages/api/handlers/java/src/main/java/com/generated/api/myapijavahandlers/handlers/SayHelloHandler.java`: - + ```java package com.generated.api.myapijavahandlers.handlers; - + import com.generated.api.myapijavaruntime.runtime.api.interceptors.DefaultInterceptors; import com.generated.api.myapijavaruntime.runtime.api.interceptors.powertools.LoggingInterceptor; import com.generated.api.myapijavaruntime.runtime.api.handlers.Interceptor; @@ -369,9 +369,9 @@ You can implement your lambda handlers in any of the supported languages, or mix import com.generated.api.myapijavaruntime.runtime.api.handlers.say_hello.SayHelloRequestInput; import com.generated.api.myapijavaruntime.runtime.api.handlers.say_hello.SayHelloResponse; import com.generated.api.myapijavaruntime.runtime.model.*; - + import java.util.List; - + /** * Entry point for the AWS Lambda handler for the SayHello operation. * The SayHello class manages marshalling inputs and outputs. @@ -385,17 +385,17 @@ You can implement your lambda handlers in any of the supported languages, or mix public List> getInterceptors() { return DefaultInterceptors.all(); } - + /** * Type-safe handler for the SayHello operation */ @Override public SayHelloResponse handle(final SayHelloRequestInput request) { LoggingInterceptor.getLogger(request).info("Start SayHello Operation"); - + // TODO: Implement SayHello Operation. `input` contains the request input. SayHelloInput input = request.getInput(); - + return SayHello500Response.of(InternalFailureErrorResponseContent.builder() .message("Not Implemented!") .build()); @@ -415,21 +415,21 @@ You can implement your lambda handlers in any of the supported languages, or mix from myapi_python_runtime.api.operation_config import ( say_hello_handler, SayHelloRequest, SayHelloOperationResponses ) - - + + def say_hello(input: SayHelloRequest, **kwargs) -> SayHelloOperationResponses: """ Type-safe handler for the SayHello operation """ LoggingInterceptor.get_logger(input).info("Start SayHello Operation") - + # TODO: Implement SayHello Operation. `input` contains the request input - + return Response.internal_failure(InternalFailureErrorResponseContent( message="Not Implemented!" )) - - + + # Entry point for the AWS Lambda handler for the SayHello operation. # The say_hello_handler method wraps the type-safe handler and manages marshalling inputs and outputs handler = say_hello_handler(interceptors=INTERCEPTORS)(say_hello) @@ -448,9 +448,9 @@ We can replace the stubbed response with a real implementation: */ export const sayHello: SayHelloChainedHandlerFunction = async (request) => { LoggingInterceptor.getLogger(request).info("Start SayHello Operation"); - + const { input } = request; - + return Response.success({ message: `Hello ${input.requestParameters.name}!`, }); @@ -484,7 +484,7 @@ We can replace the stubbed response with a real implementation: Type-safe handler for the SayHello operation """ LoggingInterceptor.get_logger(input).info("Start SayHello Operation") - + return Response.success(SayHelloResponseContent( message=f"Hello {input.request_parameters.name}!" )) @@ -521,7 +521,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured Api, SayHelloFunction, } from "myapi-typescript-infra"; - + /** * Api construct props. */ @@ -531,7 +531,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured */ readonly userIdentity: UserIdentity; } - + /** * Infrastructure construct to deploy a Type Safe API. */ @@ -540,10 +540,10 @@ Given we used the AWS PDK vended infrastructure project, this will be configured * API instance */ public readonly api: Api; - + constructor(scope: Construct, id: string, props?: ApiConstructProps) { super(scope, id); - + this.api = new Api(this, id, { defaultAuthorizer: Authorizers.iam(), corsOptions: { @@ -578,7 +578,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured ], }), }); - + // Grant authenticated users access to invoke the api props?.userIdentity.identityPool.authenticatedRole.addToPrincipalPolicy( new PolicyStatement({ @@ -597,14 +597,14 @@ Given we used the AWS PDK vended infrastructure project, this will be configured ```java hl_lines="5 44-49" package software.aws.infra.constructs; - + import com.generated.api.myapijavainfra.infra.Api; import com.generated.api.myapijavainfra.infra.ApiProps; import com.generated.api.myapijavainfra.infra.functions.SayHelloFunction; import com.generated.api.myapijavaruntime.runtime.api.operation_config.OperationConfig; - + import java.util.Arrays; - + import software.amazon.awscdk.Stack; import software.amazon.awscdk.services.apigateway.Cors; import software.amazon.awscdk.services.apigateway.CorsOptions; @@ -620,7 +620,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured import software.aws.pdk.type_safe_api.TypeSafeApiIntegration; import software.aws.pdk.type_safe_api.Integrations; import software.constructs.Construct; - + /** * Infrastructure construct to deploy a Type Safe API. */ @@ -629,10 +629,10 @@ Given we used the AWS PDK vended infrastructure project, this will be configured * API instance */ public final Api api; - + public ApiConstruct(Construct scope, String id, UserIdentity userIdentity) { super(scope, id); - + this.api = new Api(this, id, ApiProps.builder() .defaultAuthorizer(Authorizers.iam()) .corsOptions(CorsOptions.builder() @@ -668,7 +668,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured )) .build())) .build()); - + userIdentity.getIdentityPool().getAuthenticatedRole() .addToPrincipalPolicy(new PolicyStatement(PolicyStatementProps.builder() .effect(Effect.ALLOW) @@ -693,12 +693,12 @@ Given we used the AWS PDK vended infrastructure project, this will be configured from aws_pdk.type_safe_api import Authorizers, TypeSafeApiIntegration, Integrations from aws_cdk.aws_apigateway import CorsOptions, Cors from aws_cdk.aws_iam import AccountPrincipal, AnyPrincipal, Effect, PolicyDocument, PolicyStatement - + # Infrastructure construct to deploy a Type Safe API. class ApiConstruct(Construct): def __init__(self, scope: Construct, id: str, user_identity: UserIdentity, **kwargs) -> None: super().__init__(scope, id, **kwargs) - + self.api = Api(self, id, default_authorizer=Authorizers.iam(), cors_options=CorsOptions( @@ -732,7 +732,7 @@ Given we used the AWS PDK vended infrastructure project, this will be configured ) ] )) - + user_identity.identity_pool.authenticated_role.add_to_principal_policy( PolicyStatement( effect=Effect.ALLOW, @@ -920,7 +920,14 @@ After you implement your new operation, build your project again and deploy it: ```bash pdk build cd packages/infra -pdk run deploy --require-approval never +pdk deploy:dev ``` +!!!tip + If you want to quickly test changes to your lambda handler code, you can re-package the handlers, then run `pdk deploy:dev` in your infrastructure project to perform a fast [hotswap deployment](https://aws.amazon.com/blogs/developer/increasing-development-speed-with-cdk-watch/). For example from the root of your project: + + ```bash + pdk nx run myapi-typescript-handlers:package && pdk nx run infra:deploy\:dev + ``` + Try out your new API! You can use a tool such as [awscurl](https://github.com/okigan/awscurl) to make Sigv4 signed requests to your API, since we set the default authorizer to `Authorizers.iam()`. Alternatively, you can deploy the [`CloudscapeReactTsWebsiteProject`](../cloudscape-react-ts-website/index.md) and try out the [API Explorer](../cloudscape-react-ts-website/api_explorer.md). \ No newline at end of file