Creating aws serverless api using golang cdk

December 23, 2023

How to create a serverless API on AWS, using API Gateway, Lambda in Go CDK

Creating AWS Serverless Api Using Golang cdk

Pre-Reqs:

  • Go installed
  • lambda function ready to deploy
  • AWS account
  • AWS cli configured

Golang cdk quirks

Golang does not have null, so to prevent any breaking changes, aws uses jsii type library. jsii achieves cross-language communication in AWS CDK by generating language-specific bindings and glue code during the build process, ensuring consistent type systems and enabling developers to express infrastructure components in their language of choice while maintaining interoperability with other supported languages.

Creating cdk app

View Commit

The cdk init command cannot be executed in a non empty directory, so create a directory for your cdk app and run the initialisation command:

1cdk init app --language go

img.png

This creates your cdk project structure.

To install default aws cdk dependencies, run:

1go get

To install dependancies for api gateway and lambda cdks, run:

1go get github.com/aws/aws-cdk-go/awscdk/v2/awsapigateway 2go get github.com/aws/aws-cdk-go/awscdk/v2/awslambda

Configuring environment

View Commit

img.png

Creating an API Gateway

View Commit

In the NewCdkStack method call NewRestAPI from awsapigateway with the stack, api gateway name and an optional props object. I have just used nil.

1api := awsapigateway.NewRestApi(stack, jsii.String("fpl-intel-cdk"), nil)

The error is because the api is not being used (yet)

img.png

Creating the Lambda function

View Commit

I have created a function that creates & returns a new rust lambda. Any AWS Lambda runtime can be chosen. The lambdaBuilddirectory & lambdaBuildZip are for the example hello world rust lambda, found in the Github repository

1type LambdaData struct { 2 name string 3 httpMethods string 4} 5 6func CreateNewRustLambdaFunction(lambdaConfig LambdaData, stack awscdk.Stack) awslambda.Function { 7 lambdaBuildDirectory := "../hello-world/target/lambda/" 8 lambdaBuildZip := "/bootstrap.zip" 9 10 return awslambda.NewFunction(stack, jsii.String(lambdaConfig.name), &awslambda.FunctionProps{ 11 Runtime: awslambda.Runtime_PROVIDED_AL2(), 12 Code: awslambda.Code_FromAsset(jsii.String(lambdaBuildDirectory+lambdaConfig.name+lambdaBuildZip), nil), 13 Handler: jsii.String("bootstrap"), 14 MemorySize: jsii.Number(128), 15 Timeout: awscdk.Duration_Seconds(jsii.Number(30)), 16 }) 17}

Use this function in NewCdkStack to create a new lambda

1helloWorldLambda := CreateNewRustLambdaFunction(helloWorldLambdaData, stack)

img.png

Connecting the Lambda function to API Gateway

View Commit

I have created a function that takes in any aws lambda function and adds it to the api gateway, with open cors for a GET request. The resource name is the path, so to hit the endpoint, it will be /hello-world

1func AddLambdaToApiGateway(lambdaFunction awslambda.Function, lambdaConfig LambdaData, api awsapigateway.RestApi) { 2 resource := api.Root().AddResource(jsii.String(lambdaConfig.name), nil) 3 apiIntegration := awsapigateway.NewLambdaIntegration(lambdaFunction, &awsapigateway.LambdaIntegrationOptions{ 4 Proxy: jsii.Bool(true), 5 }) 6 7 corsOptions := &awsapigateway.CorsOptions{ 8 AllowOrigins: awsapigateway.Cors_ALL_ORIGINS(), 9 AllowMethods: awsapigateway.Cors_ALL_METHODS(), 10 } 11 resource.AddCorsPreflight(corsOptions) 12 resource.AddMethod(jsii.String("GET"), apiIntegration, nil) 13}

Use this function in NewCdkStack to connect the lambda with the api gateway

1AddLambdaToApiGateway(helloWorldLambda, helloWorldLambdaData, api)

Final cdkNewStack method

1func NewCdkStack(scope constructs.Construct, id string, props *CdkStackProps) awscdk.Stack { 2 var sprops awscdk.StackProps 3 if props != nil { 4 sprops = props.StackProps 5 } 6 stack := awscdk.NewStack(scope, &id, &sprops) 7 8 api := awsapigateway.NewRestApi(stack, jsii.String("fpl-intel-cdk"), nil) 9 10 helloWorldLambdaData := LambdaData{ 11 name: "hello-world", 12 httpMethods: "GET", 13 } 14 15 helloWorldLambda := CreateNewRustLambdaFunction(helloWorldLambdaData, stack) 16 AddLambdaToApiGateway(helloWorldLambda, helloWorldLambdaData, api) 17 18 return stack 19}

Deploying

Simply execute the cdk deploy command in your cdk directory

1cdk deploy

If you need to use a certain profile, use

1cdk deploy --profile profile_name

Example Deployment

img.png

Tear down

To prevent any cost surprises it is best to tear down any cdk deployments you no longer wish to keep seployed

1cdk destroy

Result

AWS Architecture Diagram

img.png

Endpoint Working

img.png


Contact