Getting started: REST API
This section describes how to get started with the Type Safe API. For more information, refer to the other user guides on particular features of this library.
Info
Select the tabs to use this library with infrastructure and lambda handlers in the same language, but you can mix and match language. For example, you could write CDK infrastructure in Java and implement some lambda handlers in Python, and others in TypeScript.
Type Safe API project structure
The TypeSafeApiProject
projen project sets up the project structure for you. Consider the following parameters when creating the project:
model
- Configure the API model. Select alanguage
for the model from either Smithy, TypeSpec or OpenAPI v3, and provideoptions.smithy
,options.typeSpec
oroptions.openapi
depending on your choice.infrastructure
- Select thelanguage
you are writing your CDK infrastructure in. A construct will be generated in this language which can be used to deploy the API.handlers
- Optionally select thelanguages
in which you wish to write lambda handlers for operations in.runtime
- Optionally configure additional generated runtime projects. Include one or morelanguages
you want to write your client and/or server-side code in. These projects contain generated types defined in your model, as well as type-safe lambda handler wrappers for implementing each operation. You'll notice runtime packages are automatically generated for languages you picked forinfrastructure
andhandlers
.documentation
- Optionally specifyformats
to generate documentation in.library
- Optionally specify additionallibraries
to generate, such as React Query hooks for use in a React website.
Create your API project
Info
We recommend you use these projects as part of an monorepo
project (eg. by specifying parent: monorepo
), as it makes setting up dependencies much easier, particularly when extending your project further with a CDK app and lambda functions.
1.) To start an empty monorepo
project, use this command:
npx projen new --from @aws/pdk monorepo-ts --package-manager=pnpm
2.) Edit your .projenrc
and configure TypeSafeApiProject
.
Tip
Use the tabs to see how to set up a project for writing infrastructure, and server-side code using specfic languages (TypeScript, Java, and Python).
import { MonorepoTsProject } from "@aws/pdk/monorepo";
import {
DocumentationFormat,
Language,
Library,
ModelLanguage,
TypeSafeApiProject,
} from "@aws/pdk/type-safe-api";
import { InfrastructureTsProject } from "@aws/pdk/infrastructure";
import { NodePackageManager } from "projen/lib/javascript";
// Create the monorepo
const monorepo = new MonorepoTsProject({
name: "my-project",
devDeps: [
"@aws/pdk",
],
packageManager: NodePackageManager.PNPM,
});
// Create the API project
const api = new TypeSafeApiProject({
name: "myapi",
parent: monorepo,
outdir: "packages/api",
// Smithy as the model language. You can also use ModelLanguage.TYPESPEC or ModelLanguage.OPENAPI
model: {
language: ModelLanguage.SMITHY,
options: {
smithy: {
serviceName: {
namespace: "com.my.company",
serviceName: "MyApi",
},
},
},
},
// CDK infrastructure in TypeScript
infrastructure: {
language: Language.TYPESCRIPT,
},
// Lambda handlers in TypeScript
handlers: {
languages: [Language.TYPESCRIPT],
}
// Generate HTML documentation
documentation: {
formats: [DocumentationFormat.HTML_REDOC],
},
// Generate react-query hooks to interact with the API from a React website
library: {
libraries: [Library.TYPESCRIPT_REACT_QUERY_HOOKS],
},
});
// Create a CDK infrastructure project
new InfrastructureTsProject({
parent: monorepo,
outdir: "packages/infra",
name: "infra",
typeSafeApis: [api],
});
monorepo.synth();
import software.aws.pdk.monorepo.MonorepoJavaProject;
import software.aws.pdk.monorepo.MonorepoJavaOptions;
import software.aws.pdk.infrastructure.InfrastructureJavaProject;
import software.aws.pdk.infrastructure.InfrastructureJavaProjectOptions;
import software.aws.pdk.type_safe_api.*;
import java.util.Arrays;
public class projenrc {
public static void main(String[] args) {
MonorepoJavaProject monorepo = new MonorepoJavaProject(MonorepoJavaOptions.builder()
.name("my-project")
.build());
TypeSafeApiProject api = new TypeSafeApiProject(TypeSafeApiProjectOptions.builder()
.name("myapi")
.parent(monorepo)
.outdir("packages/api")
.model(ModelConfiguration.builder()
.language(ModelLanguage.SMITHY)
.options(ModelOptions.builder()
.smithy(SmithyModelOptions.builder()
.serviceName(SmithyServiceName.builder()
.namespace("com.my.company")
.serviceName("MyApi")
.build())
.build())
.build())
.build())
.infrastructure(InfrastructureConfiguration.builder()
.language(Language.JAVA)
.build())
.documentation(DocumentationConfiguration.builder()
.formats(Arrays.asList(DocumentationFormat.HTML_REDOC))
.build())
.library(LibraryConfiguration.builder()
.libraries(Arrays.asList(Library.TYPESCRIPT_REACT_QUERY_HOOKS))
.build())
.handlers(HandlersConfiguration.builder()
.languages(Arrays.asList(Language.JAVA))
.build())
.build());
new InfrastructureJavaProject(
InfrastructureJavaProjectOptions.builder()
.parent(monorepo)
.outdir("packages/infra")
.name("infra")
.typeSafeApi(api)
.build());
monorepo.synth();
}
}
from aws_pdk.monorepo import MonorepoPythonProject
from aws_pdk.infrastructure import InfrastructurePyProject
from aws_pdk.type_safe_api import *
monorepo = MonorepoPythonProject(
module_name="my_project",
name="my-project",
)
api = TypeSafeApiProject(
name="myapi",
parent=monorepo,
outdir="packages/api",
model=ModelConfiguration(
language=ModelLanguage.SMITHY,
options=ModelOptions(
smithy=SmithyModelOptions(
service_name=SmithyServiceName(
namespace="com.amazon",
service_name="MyAPI"
)
)
)
),
infrastructure=InfrastructureConfiguration(
language=Language.PYTHON
),
documentation=DocumentationConfiguration(
formats=[DocumentationFormat.HTML_REDOC]
),
handlers=HandlersConfiguration(
languages=[Language.PYTHON]
),
library=LibraryConfiguration(
libraries=[Library.TYPESCRIPT_REACT_QUERY_HOOKS]
)
)
InfrastructurePyProject(
parent=monorepo,
outdir="packages/infra",
name="infra",
type_safe_api=api,
)
monorepo.synth()
3.) Given we have modified our projenrc
file we need to run the npx projen
command to synthesize our new API and infrastructure onto the filesystem. We can then run a first build with npx projen build
.
Implement a Lambda handler
The generated runtime projects include lambda handler wrappers which provide type-safety for implementing your API operations. The generated handlers
projects include generated stubs for you to implement for every operation which has been annotated accordingly:
Use the @handler
trait, and specify the language you wish to implement this operation in.
@readonly
@http(method: "GET", uri: "/hello")
@handler(language: "typescript")
operation SayHello {
input := {
@httpQuery("name")
@required
name: String
}
output := {
@required
message: String
}
}
Use the @handler
decorator, and specify the language you wish to implement the operation in.
@get
@route("/hello")
@handler({ language: "typescript" })
op SayHello(@query name: string): {
message: string;
};
Use the x-handler
vendor extension, specifying the language you wish to implement this operation in.
/hello:
get:
operationId: sayHello
x-handler:
language: typescript
parameters:
- in: query
name: name
schema:
type: string
required: true
responses:
200:
description: Successful response
content:
'application/json':
schema:
$ref: '#/components/schemas/SayHelloResponseContent'
Note
If you wish to deviate from the folder structure of the handlers
projects, or wish to implement your operations in a language not supported by Type Safe API, or through a non-lambda interation (such as a server running in a Fargate container) you can omit the @handler
trait or x-handler
vendor extension.
You can implement your lambda handlers in any of the supported languages, or mix and match languages for different operations if you prefer.
In TypeScript, you'll notice you have a lambda handler stub in packages/api/handlers/typescript/src/say-hello.ts
:
import {
sayHelloHandler,
SayHelloChainedHandlerFunction,
INTERCEPTORS,
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
*/
export const handler = sayHelloHandler(...INTERCEPTORS, sayHello);
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
:
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;
import com.generated.api.myapijavaruntime.runtime.api.handlers.say_hello.SayHello;
import com.generated.api.myapijavaruntime.runtime.api.handlers.say_hello.SayHelloInput;
import com.generated.api.myapijavaruntime.runtime.api.handlers.say_hello.SayHello500Response;
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.
*/
public class SayHelloHandler extends SayHello {
/**
* Return the interceptors for this handler.
* You can also use the @Interceptors annotation on the class to add interceptors
*/
@Override
public List<Interceptor<SayHelloInput>> 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());
}
}
In Python, you'll notice you have a lambda handler stub in packages/api/handlers/python/myapi_python_handlers/say_hello.py
:
from myapi_python_runtime.models import *
from myapi_python_runtime.response import Response
from myapi_python_runtime.interceptors import INTERCEPTORS
from myapi_python_runtime.interceptors.powertools.logger import LoggingInterceptor
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)
Note
You will notice the handler stubs make use of some default "interceptors". You can read more about interceptors here.
We can replace the stubbed response with a real implementation:
/**
* Type-safe handler for the SayHello operation
*/
export const sayHello: SayHelloChainedHandlerFunction = async (request) => {
LoggingInterceptor.getLogger(request).info("Start SayHello Operation");
const { input } = request;
return Response.success({
message: `Hello ${input.requestParameters.name}!`,
});
};
/**
* 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 SayHello200Response.of(SayHelloResponseContent.builder()
.message(String.format("Hello %s!", input.getRequestParameters().getName()))
.build());
}
def say_hello(input: SayHelloRequest, **kwargs) -> SayHelloOperationResponses:
"""
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}!"
))
Use the CDK construct
In your CDK application, using your preferred language, include the Api
construct, vended from the generated infrastructure package.
Given we used the AWS PDK vended infrastructure project, this will be configured for us already. Notice that our integrations have been mocked for us already, but we can replace them with our lambda implementation.
Tip
Use the function constructs from the generated API infrastructure project to easily create lambda functions which reference implementations in the api/handlers
projects.
Open packages/infra/src/constructs/api/myapi.ts
. Notice our API has been mocked by default. We can replace the integration for our sayHello
operation to use a lambda implementation:
import { UserIdentity } from "@aws/pdk/identity";
import { Authorizers, Integrations } from "@aws/pdk/type-safe-api";
import { Stack } from "aws-cdk-lib";
import { Cors } from "aws-cdk-lib/aws-apigateway";
import {
AccountPrincipal,
AnyPrincipal,
Effect,
PolicyDocument,
PolicyStatement,
} from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";
import {
Api,
SayHelloFunction,
} from "myapi-typescript-infra";
/**
* Api construct props.
*/
export interface ApiConstructProps {
/**
* Instance of the UserIdentity.
*/
readonly userIdentity: UserIdentity;
}
/**
* Infrastructure construct to deploy a Type Safe API.
*/
export class ApiConstruct extends Construct {
/**
* 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: {
allowOrigins: Cors.ALL_ORIGINS,
allowMethods: Cors.ALL_METHODS,
},
integrations: {
sayHello: {
integration: Integrations.lambda(new SayHelloFunction(this, "SayHello")),
},
},
policy: new PolicyDocument({
statements: [
// Here we grant any AWS credentials from the account that the prototype is deployed in to call the api.
// Machine to machine fine-grained access can be defined here using more specific principals (eg roles or
// users) and resources (ie which api paths may be invoked by which principal) if required.
// If doing so, the cognito identity pool authenticated role must still be granted access for cognito users to
// still be granted access to the API.
new PolicyStatement({
effect: Effect.ALLOW,
principals: [new AccountPrincipal(Stack.of(this).account)],
actions: ["execute-api:Invoke"],
resources: ["execute-api:/*"],
}),
// Open up OPTIONS to allow browsers to make unauthenticated preflight requests
new PolicyStatement({
effect: Effect.ALLOW,
principals: [new AnyPrincipal()],
actions: ["execute-api:Invoke"],
resources: ["execute-api:/*/OPTIONS/*"],
}),
],
}),
});
// Grant authenticated users access to invoke the api
props?.userIdentity.identityPool.authenticatedRole.addToPrincipalPolicy(
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["execute-api:Invoke"],
resources: [this.api.api.arnForExecuteApi("*", "/*", "*")],
}),
);
}
}
Open packages/infra/src/main/java/software/aws/infra/constructs/ApiConstruct.java
. Notice our API has been mocked by default. We can replace the integration for our sayHello
operation to use a lambda implementation:
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;
import software.amazon.awscdk.services.iam.AccountPrincipal;
import software.amazon.awscdk.services.iam.AnyPrincipal;
import software.amazon.awscdk.services.iam.Effect;
import software.amazon.awscdk.services.iam.PolicyDocument;
import software.amazon.awscdk.services.iam.PolicyDocumentProps;
import software.amazon.awscdk.services.iam.PolicyStatement;
import software.amazon.awscdk.services.iam.PolicyStatementProps;
import software.aws.pdk.identity.UserIdentity;
import software.aws.pdk.type_safe_api.Authorizers;
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.
*/
public class ApiConstruct extends Construct {
/**
* 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()
.allowOrigins(Cors.ALL_ORIGINS)
.allowMethods(Cors.ALL_METHODS)
.build())
.integrations(OperationConfig.<TypeSafeApiIntegration>builder()
.sayHello(TypeSafeApiIntegration.builder()
.integration(Integrations.lambda(
new SayHelloFunction(this, "SayHello")))
.build())
.build())
.policy(new PolicyDocument(PolicyDocumentProps.builder()
.statements(Arrays.asList(
// Here we grant any AWS credentials from the account that the prototype is deployed in to call the api.
// Machine to machine fine-grained access can be defined here using more specific principals (eg roles or
// users) and resources (ie which api paths may be invoked by which principal) if required.
// If doing so, the cognito identity pool authenticated role must still be granted access for cognito users to
// still be granted access to the API.
new PolicyStatement(PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.principals(Arrays.asList(new AccountPrincipal(Stack.of(this))))
.actions(Arrays.asList("execute-api:Invoke"))
.resources(Arrays.asList("execute-api:/*"))
.build()),
// Open up OPTIONS to allow browsers to make unauthenticated preflight requests
new PolicyStatement(PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.principals(Arrays.asList(new AnyPrincipal()))
.actions(Arrays.asList("execute-api:Invoke"))
.resources(Arrays.asList("execute-api:/*/OPTIONS/*"))
.build())
))
.build()))
.build());
userIdentity.getIdentityPool().getAuthenticatedRole()
.addToPrincipalPolicy(new PolicyStatement(PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.actions(Arrays.asList("execute-api:Invoke"))
.resources(Arrays.asList(this.api.getApi().arnForExecuteApi("*", "/*", "*")))
.build()));
}
}
Open packages/infra/infra/constructs/api.py
. Notice our API has been mocked by default. We can replace the integration for our sayHello
operation to use a lambda implementation:
from constructs import Construct
from myapi_python_infra.api import Api
from myapi_python_infra.functions import SayHelloFunction
from myapi_python_runtime.api.operation_config import OperationConfig
from aws_cdk import Stack
from aws_pdk.identity import UserIdentity
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(
allow_origins=Cors.ALL_ORIGINS,
allow_methods=Cors.ALL_METHODS
),
integrations=OperationConfig(
say_hello=TypeSafeApiIntegration(
integration=Integrations.lambda_(SayHelloFunction(self, 'SayHello')),
),
),
policy=PolicyDocument(
statements=[
# Here we grant any AWS credentials from the account that the prototype is deployed in to call the api.
# Machine to machine fine-grained access can be defined here using more specific principals (eg roles or
# users) and resources (ie which api paths may be invoked by which principal) if required.
# If doing so, the cognito identity pool authenticated role must still be granted access for cognito users to
# still be granted access to the API.
PolicyStatement(
effect=Effect.ALLOW,
principals=[AccountPrincipal(Stack.of(self).account)],
actions=['execute-api:Invoke'],
resources=['execute-api:/*']
),
# Open up OPTIONS to allow browsers to make unauthenticated preflight requests
PolicyStatement(
effect=Effect.ALLOW,
principals=[AnyPrincipal()],
actions=['execute-api:Invoke'],
resources=['execute-api:/*/OPTIONS/*']
)
]
))
user_identity.identity_pool.authenticated_role.add_to_principal_policy(
PolicyStatement(
effect=Effect.ALLOW,
actions=['execute-api:Invoke'],
resources=[self.api.api.arn_for_execute_api('*', '/*', '*')]
)
)
Add a new operation
To add a new operation to your API, follow these steps.
Define the operation in your model
Add the new operation in the model
project, for example:
In model/src/main/smithy/main.smithy
, or another .smithy
file somewhere in model/src/main/smithy
, define the operation:
/// Documentation about your operation can go here
@http(method: "POST", uri: "/goodbye")
@handler(language: "typescript") // <- you can also choose "python" or "java"
operation SayGoodbye {
input := {
@required
name: String
}
output := {
@required
message: String
}
}
Register the operation to the service in main.smithy
:
@restJson1
service MyService {
version: "1.0"
operations: [
SayHello
SayGoodbye // <- add your new operation here
]
}
In model/src/main.tsp
or another .tsp
file somewhere in the model/src
directory, define the operation:
namespace MyApi; // <- ensure the namespace is the same as in main.tsp if defining in another file
/**
* Documentation about the operation can go here
*/
@post
@route("/goodbye")
@handler({ language: "typescript" }) // <- you can also choose "python" or "java"
op SayGoodbye(
name: string,
): {
message: string;
};
If you defined your operation in a different file, you must import it in model/src/main.tsp
:
import "./operations/say-goodbye.tsp";
In model/src/main/openapi/main.yaml
, add the new operation under paths
, and any new schemas under components.schemas
.
paths:
...
# Add the operation under "paths"
/goodbye:
post:
operationId: sayGoodbye
# You can also choose "python" or "java" for the handler language below
x-handler:
language: "typescript"
requestBody:
content:
application/json:
# We can define the request body inline or use a ref
schema:
$ref: "#/components/schemas/SayGoodbyeRequest"
responses:
200:
description: Successful Response
content:
application/json:
# We can define the response body inline or use a ref
schema:
$ref: "#/components/schemas/SayGoodbyeResponse"
components:
schemas:
# Add components here
SayGoodbyeRequest:
type: object
properties:
name:
type: string
required:
- name
SayGoodbyeResponse:
type: object
properties:
message:
type: string
required:
- message
Note
You can split your API into multiple yaml
files. For more information, refer to Using OpenAPI.
Build your project
To run a build in the root of your monorepo, use the npx projen build
command:
npx projen build
The build will regenerate the infrastructure, runtime, documentation, and library projects based on your updated model. It will also generate a new stub for your new operation if you specified the @handler
trait in Smithy or x-handler
vendor extension in OpenAPI.
As you must define an integration for every operation, you may see the following build error in your CDK application.
TSError: тип Unable to compile TypeScript:
src/constructs/api/myapi.ts: error TS2741: Property 'sayGoodbye' is missing in type '{ sayHello: { integration: Integration; }; }' but required in type 'OperationConfig<TypeSafeApiIntegration>'.
This is expected, so follow these steps to add an integration.
Add an integration
In your CDK application, add an integration for your new operation in the Api
construct:
new Api(this, "MyApi", {
...
integrations: {
sayHello: {
integration: Integrations.lambda(new SayHelloFunction(this, "SayHello")),
},
// Add the new integration here
sayGoodbye: {
integration: Integrations.lambda(new SayGoodbyeFunction(this, "SayGoodbye")),
},
},
...
});
new Api(this, "Api", ApiProps.builder()
...
.integrations(OperationConfig.<TypeSafeApiIntegration>builder()
.sayHello(TypeSafeApiIntegration.builder()
.integration(Integrations.lambda(
new SayHelloFunction(this, "SayHello")))
.build())
.sayGoodbye(TypeSafeApiIntegration.builder()
.integration(Integrations.lambda(
new SayGoodbyeFunction(this, "SayGoodbye")))
.build())
.build())
...
.build());
Api(self, 'Api',
...
integrations=OperationConfig(
say_hello=TypeSafeApiIntegration(
integration=Integrations.lambda_(SayHelloFunction(self, 'SayHello')),
),
say_goodbye=TypeSafeApiIntegration(
integration=Integrations.lambda_(SayGoodbyeFunction(self, 'SayGoodbye')),
),
),
...
)
Implement the Lambda handler
As described above, you'll find a lambda handler stub for your new operation, which you can edit as you wish.
Deploy your project
After you implement your new operation, build your project again and deploy it:
npx projen build
cd packages/infra
npx projen deploy:dev
Tip
If you want to quickly test changes to your lambda handler code, you can re-package the handlers, then run npx projen deploy:dev
in your infrastructure project to perform a fast hotswap deployment. For example from the root of your project:
npx nx run myapi-typescript-handlers:package && npx nx run infra:deploy\:dev
Try out your new API! You can use a tool such as awscurl to make Sigv4 signed requests to your API, since we set the default authorizer to Authorizers.iam()
. Alternatively, you can deploy the CloudscapeReactTsWebsiteProject
and try out the API Explorer.