12 minute read
Building a Serverless Express and TypeScript Application With AWS Lambda
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:
```terminal
node -v
```
Next, you need to install TypeScript. You can run the following command:
```terminal
npm install -g typescript
```
This will install TypeScript globally on your machine. You can check the version by running the following:
```terminal
tsc -v
```
Finally, you need to install the AWS CLI. You can do this by running the following command:
```terminal
npm install -g aws-cli
```
Once the AWS CLI is installed, you will need to configure it with your AWS credentials. You can do this by running the following command:
```terminal
aws configure
```
Code language: SQL (Structured Query Language) (sql)
After 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!
```terminal
mkdir serverless-express-ts && cd serverless-express-ts
```
Next, you'll initialize our project with npm:
```terminal
npm init -y
```
Code language: SQL (Structured Query Language) (sql)
This 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:
```terminal
npm install express @types/express ts-node --save-dev
Code language: SQL (Structured Query Language) (sql)
Next, 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:
```terminal
mkdir src && touch src/app.ts && touch tsconfig.json
```
The tsconfig.json file should contain the following:
```json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
}
},
"include": ["src/**/*"]
}
```
Code language: Arduino (arduino)
Now add a simple Express application to our src/app.ts file:
```node
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');
});
```
Code language: C# (cs)
Notice 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:
```node
"scripts": {
"start": "ts-node src/app.ts"
},
```
Now you can start the application by running:
```terminal
npm start
```
Code language: Go (go)
You 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:
```terminal
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
```
Code language: Elixir (elixir)
After 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 <ACCOUNT_ID> and <ROLE_NAME> with your own.
Next, let’s create a new API Gateway by running the following command:
```terminal
aws apigateway create-rest-api --name "Serverless Express TS"
```
This 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:
```terminal
aws apigateway create-resource --rest-api-id <API_ID> --parent-id <ROOT_RESOURCE_ID> --path-part "{proxy+}"
Code language: SQL (Structured Query Language) (sql)
That code creates a new resource named “{proxy+}” and sets it up as a child of the root resource. Now go ahead and replace <API_ID> and <ROOT_RESOURCE_ID> with the appropriate values from the previous step.
After that, create a new method for the resource. Here’s how:
```terminal
aws apigateway put-method --rest-api-id <API_ID> --resource-id <RESOURCE_ID> --http-method ANY --authorization-type NONE
```
Code language: Go (go)
This command creates a new method for the resource. One that accepts any HTTP method and does not require authorization. Always replace <API_ID> and <RESOURCE_ID> with the appropriate values from the previous step.
Here’s how to create the integration for this method:
```terminal
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
```
Code language: Elixir (elixir)
This 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:
```terminal
aws apigateway create-deployment --rest-api-id <API_ID> --stage-name prod
```
Code language: Go (go)
Notice 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:
```terminal
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
```
Code language: SQL (Structured Query Language) (sql)
There 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:
```terminal
aws lambda update-function-code \
--function-name my-express-app \
--zip-file fileb://path/to/deployment.zip
```
Code language: SQL (Structured Query Language) (sql)
After the function is created, test it by sending a test event to it using the aws lambda invoke command. Here it is:
```terminal
aws lambda invoke \
--function-name my-express-app \
--payload '{"httpMethod": "GET", "path": "/"}' \
--log-type Tail \
response.json
```
Code language: PHP (php)
This 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:
```terminal
aws logs filter-log-events \
--log-group-name /aws/lambda/my-express-app \
--start-time <START_TIME> \
--end-time <END_TIME>
```
Code language: Arduino (arduino)
That 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.
Want to Dive Deeper?
For additional education and relevant content, be sure to check out the following articles:
- Safely Moving Away From Monoliths: Chapter 1
- Safely Moving Away From Monoliths: Chapter 2
- #StopTheDevHorror
Deliver Features That Matter, Faster with Split
Split is a feature management platform that attributes insightful data to everything you release. Whether your team is looking to test in production, perform gradual rollouts, or experiment with new features–Split ensures your efforts are safe, visible, and highly impactful. What a Release. Get going with a free account today, Schedule a demo to learn more, or contact us for further questions and support.