Get Started
smithy-cdk
substitutes CDK resources into an OpenAPI model specification file generated by Smithy, so that a REST API Gateway is deployed in one go with proper integrations and permissions for API paths. See the project README for more motivations.
The development cycle works like this:
- Define API model in Smithy files. Where an AWS Service is needed for a URI, like the ARN of a lambda function, instead put a
${substitution key}
- Build the Smithy model
- Create a
SmithyApiDefinition
with generated JSON model, and supplySmithyIntegrations
to inject CDK Tokens
Example
In your Smithy build file configure API Gateway settings. This example shows settings for enabling smithy -> open-api conversion and API Gateway extensions.
smithy-build.json
{
"version": "1.0",
"sources": ["models"],
"maven": {
"dependencies": [
"software.amazon.smithy:smithy-openapi:1.41.1",
"software.amazon.smithy:smithy-aws-traits:1.41.1",
"software.amazon.smithy:smithy-aws-apigateway-openapi:1.42.0"
]
},
"projections": {
"openapi-conversion": {
"plugins": {
"openapi": {
"service": "smithycdk#HiByeApi",
"protocol": "aws.protocols#restJson1",
"version": "3.0.2", // <---- current latest OpenAPI version supported by API Gateway
"apiGatewayDefaults": "2023-08-11",
"disableCloudFormationSubstitution": false
}
}
}
}
}
Now in the Smithy API model add API Gateway traits. This adds a lambda integration to the /hi
endpoint. The URI field is set to a substitution key SayHiLambda
by wrapping it in ${}
.
hi-bye-api.smithy
@readonly
@http(method: "GET", uri: "/hi")
@integration(
type: "aws_proxy",
uri: "${SayHiLambda}",
httpMethod: "POST"
)
operation SayHi {
input: SayHiInput
output: SayHiOutput
}
After running smithy build
the following open-api JSON is generated, this snippet shows the JSON for the API Gateway integration of the /hi
endpoint.
HiByeApi.openapi.json
{
/* ... */
"x-amazon-apigateway-integration": {
"type": "aws_proxy",
"uri": {
"Fn::Sub": "${SayByeLambda}"
},
"httpMethod": "POST"
}
/* ... */
}
Then, in CDK code supply a SmithyLambdaIntegration
to match the substitution key SayHiLambda
. Permissions will be automatically created for the API Gateway endpoint to invoke the Lambda.
smithy-cdk-example-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as node_lambda from 'aws-cdk-lib/aws-lambda-nodejs'
import * as lambda from 'aws-cdk-lib/aws-lambda'
import { SpecRestApi } from 'aws-cdk-lib/aws-apigateway';
import { Construct } from 'constructs';
import { SmithyApiDefinition, SmithyLambdaIntegration } from 'smithy-cdk';
import * as path from 'path'
export class SmithyCdkExampleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Nodejs Lambda
const sayHiLambda = new node_lambda.NodejsFunction(this, 'sayhi', {
description: 'Greets the caller',
runtime: lambda.Runtime.NODEJS_20_X
});
// Loads Smithy model into JSON from file
const modelJson = buildSmithyModel({
srcDir: path.join(__dirname, 'smithy'),
modelName: 'HiByeApi'
});
// Create the API Gateway REST API
new SpecRestApi(this, 'hiByeApi', {
apiDefinition: new SmithyApiDefinition(modelJson, {
'SayHiLambda': new SmithyLambdaIntegration(sayHiLambda, { allowTestInvoke: true })
})
});
}
}
After running cdk synth
we can see that the lambda integration has been created for the api endpoint, and that permissions have been created in the CloudFormation template
cloudformation output
...
/hi:
get:
operationId: SayHi
parameters:
- name: name
in: query
schema:
type: string
required: true
responses:
"200":
description: SayHi 200 response
content:
application/json:
schema:
$ref: "#/components/schemas/SayHiResponseContent"
x-amazon-apigateway-integration:
type: aws_proxy
uri:
Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- ":apigateway:"
- Ref: AWS::Region
- :lambda:path/2015-03-31/functions/
- Fn::GetAtt:
- sayhi6FD0447D
- Arn
- /invocations
httpMethod: POST
...
aws:cdk:path: SmithyCdkExampleStack/hiByeApi/ApiPermission.Test.SmithyCdkExampleStackhiByeApiDFA9205D.GET..bye
hiByeApiApiPermissionSmithyCdkExampleStackhiByeApiDFA9205DGEThi1307E9C2:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName:
Fn::GetAtt:
- sayhi6FD0447D
- Arn
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- ":execute-api:"
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- ":"
- Ref: hiByeApiF6F479FD
- /
- Ref: hiByeApiDeploymentStageprodD116C929
- /GET/hi
View the full code for this example