Serverless architecture has become increasingly popular due to its cost-effectiveness and scalability. Using services such as AWS Lambda, developers can build and deploy their applications without needing servers or infrastructure. In this blog post, you’ll learn how to make a serverless Express and TypeScript application using AWS Lambda and API Gateway.
Express is an infamous Node.js framework that simplifies building web applications. TypeScript, on the other hand, is a typed superset of JavaScript that can be transferred to plain JavaScript and run in any browser or JavaScript environment. Together, these technologies make creating robust and scalable web applications accessible.
What’s AWS Lambda? It’s a service that allows you to run your code without provisioning or managing servers. With AWS Lambda, you only pay for your computing time and don’t need to worry about scaling or maintaining servers.
Let’s also tackle API Gateway! This is a service that allows you to create, publish, and manage APIs. The benefit of an API Gateway is that it can create a RESTful API for your Lambda function, which a web or mobile application can consume.
Today, we’ll cover a few different topics with code examples for each. Here’s what we’ll be diving into.
- Setting up the development environment
- Creating a new Express and TypeScript application
- Configuring AWS Lambda and API Gateway
- Deploying the application to AWS
- Testing and debugging the application
- Conclusion and next steps
By the end of this tutorial, the hope is to have a fully-functioning serverless Express and TypeScript application running on AWS Lambda and API Gateway. Let’s get started, shall we?
Setting up the Development Environment
Before You can begin building a serverless Express and TypeScript application, you need to set up a development environment. Start by installing Node.js, TypeScript, and the AWS CLI (if you don’t already have them).
When installing Node.js, download the installer from the official website and follow the instructions. Once it’s on your machine, be sure to check the version by running the following command in your terminal:
node -v
BashNext, you need to install TypeScript. You can run the following command:
npm install -g typescript
BashThis will install TypeScript globally on your machine. You can check the version by running the following:
tsc -v
BashFinally, you need to install the AWS CLI. You can do this by running the following command:
npm install -g aws-cli
BashOnce the AWS CLI is installed, you will need to configure it with your AWS credentials. You can do this by running the following command:
aws configure
BashAfter you’ve entered the code, you’ll be prompted you to enter your AWS access key, secret key, and the region you want to use. Hopefully you’ve got it written down (or it’s filed somewhere safe in your noggin).
Type it in, and you should be off to the races!
Creating a New Express and TypeScript Application
Okay, so you’re development environment is ready—that’s great news! Now let’s start creating your new Express and TypeScript application. The first thing you’ll need to do is create a fresh directory. Specify it for your project and navigate right there:
mkdir serverless-express-ts && cd serverless-express-ts
BashNext, you’ll initialize our project with npm
:
npm init -y
BashThis step will create a package.json
file in your project directory containing your application’s dependencies
and scripts
.
Next, install the necessary dependencies for your project. These include express
, @types/express
, and ts-node
. Here’s what that code looks like:
npm install express @types/express ts-node --save-dev
BashNext, create an src
directory to hold our TypeScript files and a src/app.ts
file, which will be the entry point for our application. You’ll need to create a tsconfig.json
file in the root of our project, which will configure TypeScript for our application:
mkdir src && touch src/app.ts && touch tsconfig.json
BashThe tsconfig.json
file should contain the following:
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
}
},
"include": ["src/**/*"]
}
JSONNow add a simple Express application to our src/app.ts
file:
// src/app.ts
import express from "express";
const app = express();
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(3000, () => {
console.log("Server started on http://localhost:3000");
});
TypeScriptNotice how this simple Express application listens on port 3000
. It should return a “Hello World!” message once the root route is accessed. What a friendly greeting!
You can then run this application, but you must add a script to our package.json
file. Call this script start, and it will use ts-node
to run our src/app.ts
file:
// package.json
{
"scripts": {
"start": "ts-node src/app.ts"
}
}
JSONNow you can start the application by running:
npm start
BashYou should see the message: Server started on http://localhost:3000
in your terminal. At this point, you can access your application by navigating to http://localhost:3000
in your browser.
With a working Express and TypeScript application, you can proceed to the next step of configuring AWS Lambda and API Gateway.
It’s worth noting that there aren’t any test or build scripts in this example. However, it’s still best practices to keep them in a real-world project. You could always use other tools like webpack or babel to transpile and bundle your production application. Options do exist!
It’s also worth noting that this example assumes you have the AWS CLI installed and configured on your machine. If you haven’t done that already, you’ll need to make it happen before proceeding to the next step.
Now that you’ve walke through those steps, you’re ready to configure AWS Lambda and API Gateway to run our serverless application—boom!
Configuring AWS Lambda and API Gateway
Let’s dig in!
First, you’ll need to create a new AWS Lambda function. You can do this using the AWS CLI by running the following command:
aws lambda create-function --function-name serverless-express-ts --runtime nodejs12.x --handler dist/app.handler --role arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME> --zip-file fileb://dist/app.zip
BashAfter punching in that command, a new Lambda function named serverless-express-ts
should pop it. Notice the runtime of Node.js 12.x
, using the dist/app.handler
file as the handler and the dist/app.zip
file as the deployment package. The role
flag is used to specify the IAM role that the function will use. Be sure to replace and with your own.
Next, let’s create a new API Gateway by running the following command:
aws apigateway create-rest-api --name "Serverless Express TS"
BashThis command creates a new REST API named “Serverless Express TS”. You should see the id of the created API in the response. Now you’ll create a new resource for the API:
aws apigateway create-resource --rest-api-id <API_ID> --parent-id <ROOT_RESOURCE_ID> --path-part "{proxy+}"
BashThat code creates a new resource named {proxy+}
and sets it up as a child of the root
resource. Now go ahead and replace and with the appropriate values from the previous step.
After that, create a new method for the resource. Here’s how:
aws apigateway put-method --rest-api-id <API_ID> --resource-id <RESOURCE_ID> --http-method ANY --authorization-type NONE
BashThis command creates a new method for the resource. One that accepts any HTTP method and does not require authorization. Always replace and with the appropriate values from the previous step.
Here’s how to create the integration for this method:
aws apigateway put-integration --rest-api-id <API_ID> --resource-id <RESOURCE_ID> --http-method ANY --type AWS --integration-http-method ANY --uri arn:aws:apigateway:<REGION>:lambda:path/2015-03-31/functions/arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:serverless-express-ts/invocations
BashThis command creates an integration between the method and the Lambda function you created earlier, using the ANY HTTP method and allowing the Lambda function to be invoked using the ANY
HTTP method. Replace <API_ID>
, <RESOURCE_ID>
, <REGION>
, and <ACCOUNT_ID>
with the appropriate values.
Okay, almost done. As a final step, you’ll now deploy the API:
aws apigateway create-deployment --rest-api-id <API_ID> --stage-name prod
BashNotice how it deploys the API to a new stage named “prod”. Be ready to replace <API_ID>
with the appropriate value and—wallah! You have successfully configured AWS Lambda and API Gateway to run a serverless Express and TypeScript application.
You can now test the API by sending a request to the endpoint provided in the response of the create-deployment command.
The above code examples are a basic setup for running an Express application on AWS Lambda and API Gateway. Depending on your specific use case, you may need to add additional resources, methods, and integrations to utilize the services’ capabilities in fully. Don’t be shy about using the serverless framework to automate the deployment process, making things even more efficient.
Deploying the application to AWS
Now for the grand finale of building a serverless Express and TypeScript application with AWS and Lamda! It’s all about deploying the application to AWS!
The process involves packaging the application code and dependencies and uploading it to AWS Lambda.
To deploy the application, you must have the AWS CLI installed and configured on your machine. Once that’s done, use the aws lambda create-function
command to create a new AWS Lambda function. Take this junction to reach that function:
aws lambda create-function \
--function-name my-express-app \
--runtime nodejs14.x \
--role <ROLE_ARN> \
--handler index.handler \
--zip-file fileb://path/to/deployment.zip
BashThere you have it. A new function named my-express-app
is created with the runtime set to Node.js 14.x
. Replace <ROLE_ARN>
with the ARN
of the IAM role that you created earlier. Set the handler parameter is to index.handler
, the default handler for an Express application. The zip-file
parameter should also be set to the path of the deployment package, which is a zip file containing the code and dependencies.
Don’t forget to use the aws lambda update-function-code
command to update the code:
aws lambda update-function-code \
--function-name my-express-app \
--zip-file fileb://path/to/deployment.zip
BashAfter the function is created, test it by sending a test event to it using the aws lambda invoke
command. Here it is:
aws lambda invoke \
--function-name my-express-app \
--payload '{"httpMethod": "GET", "path": "/"}' \
--log-type Tail \
response.json
BashThis will invoke the function and send the test event payload to it. The response of the function will be written to the response.json file. The log-type parameter should be set to Tail, which means that the last 4 KB of the log stream will be returned in the response.
Prop tip: You can also use the AWS Management Console to deploy your code, and this can be done by going to the AWS Lambda service. Once you’ve done that, find your function and upload your code from there.
Now you’re live on AWS Lambda and ready to go!
Testing and Debugging a Serverless Express and TypeScript Application
Okay, wait just one second! You can’t call it a day until you check your application for bugs. Luckily, you can quickly test and debug your application on AWS Lambda with the right tools and techniques.
One way to test your application is by using the AWS CLI to invoke the function and inspect the response.
Another way to test your application is by using the AWS Management Console. In the AWS Lambda service, quickly locate your function and then test it using the built-in test function; this will allow you to simulate different input events to your function and monitor the results for bugs.
AWS Lambda automatically generates logs for each invocation of a function. You can view these logs in the CloudWatch service. And, if your function is not working as expected, you can always use the logs generated by AWS Lambda to debug the issue.
Here’s another option: Use the console.log()
statement to print debug information to the logs. To view the logs, you can use the aws logs filter-log-events
command. Like this:
aws logs filter-log-events \
--log-group-name /aws/lambda/my-express-app \
--start-time <START_TIME> \
--end-time <END_TIME>
BashThat should return all the log events for the specified log group between the start and end time.
As an alternate strategy, you can choose to debug your application by using breakpoints; AWS Lambda supports debugging your code using the AWS Toolkit for Visual Studio Code. Go in to set up breakpoints, step through the code, inspect variables, and quickly identify, and fix any issues.
That’s if for now. We hope these steps we’re helpful and the commands got you what you needed.
Switch It On With Split
The Split Feature Data Platform™ gives you the confidence to move fast without breaking things. Set up feature flags and safely deploy to production, controlling who sees which features and when. Connect every flag to contextual data, so you can know if your features are making things better or worse and act without hesitation. Effortlessly conduct feature experiments like A/B tests without slowing down. Whether you’re looking to increase your releases, to decrease your MTTR, or to ignite your dev team without burning them out–Split is both a feature management platform and partnership to revolutionize the way the work gets done. Schedule a demo to learn more.
Get Split Certified
Split Arcade includes product explainer videos, clickable product tutorials, manipulatable code examples, and interactive challenges.