Hey there! Welcome to this new blog post!
I am currently learning a thing or 2 about AWS CDK, Lambda and Apollo GraphQL. In this post I would like to explain how to setup your AWS CDK and deploy your Apollo GraphQL API to Lambda.
Have a nice read :)
Setup AWS CDK
In order to follow this post I assume you have configured your AWS CLI with your credentials. If not, you can do that following this link
Assuming you have a fully functioning Apollo GraphQL API that runs on your local machine, it's now time to setup the AWS CDK and make sure your API gets deployed to AWS Lambda successfully.
Let's begin with the libraries we need to install. Apollo has 2 libraries. The normal one which is apollo-server
and the lambda one which is apollo-server-lambda
. We need to use the latter here.
In addition to this we also need 2 other libraries. Namely: aws-cdk-lib
and esbuild
The reason we need to use apollo-server-lambda
here and not apollo-server
is because the former exposes a createHandler()
method. We need this method to create a handler method for our AWS lambda function.
Once we have installed these libraries, we need to create a new directory in the root of our project. Let's call it cdk
. Inside this directory let's create a stack.ts
file and a cdk.json
file.
Inside the stack.ts
file we need to write our main logic that will be responsible for the creation of our lambda function and our API gateway.
Before we dive into that, let's import a few dependencies first:
import * as cdk from "aws-cdk-lib"
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apiGateway from "aws-cdk-lib/aws-apigateway"
import { join } from 'path'
Next, we need to create a new class. This class will extend from the cdk.Stack
class. Inside this class we can define any AWS Instance we would like to implement in our stack, but for now we will stick to the lambda function and the API gateway.
class Stack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const lambdaFunction = new NodejsFunction(this, "music-api-gql", {
runtime: lambda.Runtime.NODEJS_14_X,
handler: "graphqlHandler",
entry: join(__dirname, '../src/handler.ts'),
bundling: {
minify: true
}
})
}
}
We use the NodejsFunction
constructor as opposed to the normal Function
constructor. The reason behind this is that the NodejsFunction
constructor compiles and transpiles our TS code and utilizes the esbuild
lib under the hood to bundle our code into a single file. This is exactly what we want because that makes the assets that we want to deploy to AWS Lambda significantly smaller.
If we do not bundle our code, we most likely need to zip our JS build files ourselves and add our node_modules to it. I tried this myself, but I ran into a limitation. AWS Lambda has a limit on the unzipped package size (our code) which is maxed at 250MB. Including all node_modules quickly brings the package size > 250MB which is the reason my deployment kept failing.
Here we use the NodejsFunction
constructor which takes care of the bundling so we do not have to worry about this :)
Looking back at our code example, we can see that we have a couple of properties inside our constructor.
- runtime -> Specifies our runtime environment
- handler -> Specifies our handler function (the one we export with
createHandler()
). Since our code is bundles into 1 file, we do not traverse through other directories here, but look in the root for our handler function. - entry -> Specifies the entry point of our unbundled TS files.
- bundling -> Specifies custom bundling logic for
esbuild
.
Next we create a new API gateway for our lambda function. This happens below the definition of our lambda function.
new apiGateway.LambdaRestApi(this, "music-api-gatway", {
handler: lambdaFunction
})
Now that we have defined the stack we want to use, we need to use the class to initiate it all:
const app = new cdk.App()
new Stack(app, "my-cdk-stack", {
stackName: 'my-cdk-stack'
})
Now our stack.ts
file is complete (for now). Let's have a look at our cdk.json. The aws-cdk commands we will be using make use of this file for it's configuration. For now defining the path of our stack class will suffice.
{
"app": "npx ts-node --prefer-ts-exts ./stack.ts"
}
Deployment to AWS Lambda using the CDK
If you have followed the steps above and are at this stage. It means you can start deploying the API to AWS Lambda!
First we need to issue the following command:
npx aws-cdk synth
→ This produces (synthesizes) an AWS CloudFormation template for each stack defined in the stack.ts
class. This also bundles your code and places it in the cdk.out
folder which the deployment command will use to actually deploy the stack.
When this is done successfully we can issue the deploy command:
npx aws-cdk deploy
You should now see a URI in your terminal. This is your lambda API gateway URI. If all went well, that URI exposes your Apollo GraphQL API! :)
Discussion (0)