Shifting Your Node Express APIs to Serverless
Tags: node, typescript, serverless, webdev
Published: 2019-09-15 23:19:20

---
title: Shifting Your Node Express APIs to Serverless
published: true
tags: node, typescript, serverless, webdev
description: Your node and express app has proven to be a staple for serving your API endpoints. But what if you could write your same APIs and not worry about server setup or maintenance? Leaning on your express experience you can shift your APIs to serverless with minimal effort resulting in an API that scales well and lets you focus on the code, not the servers.
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ea09p7nqzplingmhaisg.jpg
canonical_url: https://johnpapa.net/shifting-your-node-express-apis-to-serverless/
---

If you have Express APIs you are not alone. But have you ever considered shifting this server based API model to a serverless one? Stick with me and this by the end of this article you'll see how to do it and have a working example to try for yourself.

> Update: [Try everything you see in this article in this hands-on tutorial](https://docs.microsoft.com/en-us/learn/modules/shift-nodejs-express-apis-serverless/?wt.mc_id=devto-blog-jopapa)

I love Node and Express for creating APIs! However, these require a server and paying for that server in the cloud. Shifting to serverless alleviates the cost, the server upkeep, helps scale up and down easily, and reduces the surface area of the middleware required for a robust Express app. Is it perfect? No, of course not! But this is a solid option if these factors affect you. You'll learn how to shift your Node Express APIs to Serverless Functions in this article.

![Shifting to Serverless](https://thepracticaldev.s3.amazonaws.com/i/1etett7tpuyeutfj00zr.jpg)

> This article is part of [#ServerlessSeptember](https://dev.to/azure/serverless-september-content-collection-2fhb). You'll find other helpful articles, detailed tutorials, and videos in this all-things-Serverless content collection. New articles are published every day in the month of September.

> Find out more about how Microsoft Azure enables your Serverless functions at [https://docs.microsoft.com/azure/azure-functions](https://docs.microsoft.com/en-us/azure/azure-functions/?WT.mc_id=servsept_devto-blog-cxa).

## What You'll Learn

We'll start by exploring and running the Node and Express APIs in the sample project. Then we'll walk through creating an Azure Functions app followed by refactoring the Express routes and data calls to the Azure Functions app. Finally, we'll explore the results together. Through this you'll learn to:

1. create an Azure Function app
1. refactor existing Express APIs to Azure Functions
1. understand the differences between the approaches

> While this article walks through the steps to shift your APIs from Express to Azure Functions, you can also follow along with the completed sample project on GitHub.

We'll walk through the code and the steps together, and at the end I share links to everything you need to get started and try this for yourself.

## Planning the Shift to Serverless

Before shifting the app to serverless, let's think about why we might want to do this and what effort it might take to perform the shift.

First, the Express app requires a server which you must configure and maintain. It would be nice to alleviate some of this effort and cost.

Express apps often have a long list of middleware and logic to start the server. This sample project has a minimal amount of middleware, but you'd certainly want more in a production app with more concerns (ex: security) and features (ex: logging). While Azure Functions don't make this go away entirely, there is less logic and less code to start Azure Functions. Often there is very little code and some configuration. What does this mean in a concrete example? Well, for this sample app the _server.ts_ file effectively goes away.

So why make this shift? Overall there is less to think about with serverless.

## About the Sample Project

What's in the [sample project on GitHub](https://github.com/johnpapa/express-to-functions) that you'll learn about in this article? Great question!

The project represents a simple Node Express APIs app in TypeScript that is shifted to Azure Functions.

But what if you aren't using TypeScript? That's fine. If your Express app is using JavaScript, feel free to shift it to Azure Functions using JavaScript.

The client app is Angular, however it could just as easily be Vue or React. The heroes and villains theme is used throughout the app.

While we will use an Angular app, one of the great things about Azure Functions is that you can run it locally on you computer, debug it, and call HTTP functions using tools like a browser, Postman, Insomnia (as shown below).
![Calling Serverless](https://thepracticaldev.s3.amazonaws.com/i/1hhzrhiktn18umnpy1k2.jpg)

## Getting Started

Let's start by getting the code and setting up the development environment. Follow these steps to prepare the code.

1. Clone this repository
1. Install the npm packages
1. Build the Node Express and the Angular code

   ```bash
   git clone https://github.com/johnpapa/express-to-functions.git
   cd express-to-functions
   npm install
   npm run node-ng:build
   ```

1. Make a copy of the _env.example_ file named _.env_, in the root of the project. It should contain the following code.

_.env_

```
NODE_ENV=development
PORT=7070
WWW=./
```

> Environment Variables: Applications may have very important environment variables located in the root in _.env_ file. This file is not checked into GitHub because it may contain sensitive information.

Now our code is ready for us to use it. But before we do, let's take a step back and see what we have.

## Node and Express APIs

Now let's explore the [sample project on GitHub](https://github.com/johnpapa/express-to-functions).

This is a conventional Node and Express application that serves the following eight endpoints.

| method | route endpoint |
| ------ | -------------- |
| GET    | heroes         |
| POST   | heroes         |
| PUT    | heroes:id      |
| DELETE | heroes/:id     |
| GET    | villains       |
| POST   | villains       |
| PUT    | villains:id    |
| DELETE | villains/:id   |

The structure of the Node Express app is straight-forward and contained in the _server_ folder.

```text
server
 | - routes
 | | - hero.routes.ts  👈 The hero routes
 | | - index.ts
 | | - villain.routes.ts
 | - services
 | | - data.ts         👈 The hero data (could be database API calls)
 | | - hero.service.ts 👈 The logic to get the hero data
 | | - index.ts
 | | - villain.service.ts
 | - index.ts
 | - server.ts         👈 The Express server
 | - tsconfig.json
```

The entry point is the _server/index.ts_ file which runs the _server.ts_ code to start the Express server. Then the routes (such as /heroes) are then loaded from the _/routes_ folder. These routes execute the appropriate code in the _/services_ folder. The _data.ts_ file is where the app defines the data store configuration.

For example, when the client app makes a HTTP GET to the _/heroes_ route, the route executes the logic in the _/services/hero.service.ts_ file to get the heroes.

Feel free to explore the code for the Express logic in the _server_ folder on your own.

Here is a screen capture of the running application.

![Tour of Heroes](https://thepracticaldev.s3.amazonaws.com/i/bp83wqpwc4ne6lot6x8d.jpg)

### Run and Debug the Express App

When I want to become familiar with an app, I find it helpful to run and step through an app with the debugger. Let's do this together.

Let's start by opening the app in Visual Studio Code.

1. Open _proxy.conf.json_ and change the port to **7070** (our Express app)
1. Open the VS Code Command Palette **F1**
1. Type **View: Show Debug** and press **ENTER**
1. Select **Debug Express and Angular**
1. Press **F5**
1. Notice the browser opens to <http://localhost:7070>

You may now set breakpoints in the Express and Angular code.

Here the debugger is stopped on a breakpoint in the Angular app.

![Debugging Angular](https://thepracticaldev.s3.amazonaws.com/i/ak08usxnehfpgfj8vg9a.jpg)

Here the debugger is stopped on a breakpoint in the Express app.

![Debugging Express](https://thepracticaldev.s3.amazonaws.com/i/z328yfch0tflkw46wk88.jpg)

> The files _.vscode/launch.json_ and _.vscode/tasks.json_ are integral to the debugging experience for this project. I encourage you to explore those files and copy/refactor their contents for your own purposes.

## Making the Shift

Now that we've run the app and explored where we started with Express, let's plan the shift from Express to serverless. I like to solve problems by breaking them down into smaller problems. In this case, et's start by breaking down the Node Express app can be broken down into its three main areas:

1. The Express server ( mostly in _server.ts_)
1. The routes (_routes/_\*)
1. The data access logic (_services/_.service.ts\*)

We'll take these one at a time as we make the shift for all of these. Let's start with shifting from the Express server to Azure Functions.

### Express 👉 Azure Functions

The Express server runs the API on a server. You can create an Azure Functions project to run the APIs instead. I recommend using the [VS Code Extension for Azure Functions](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions&WT.mc_id=devto-blog-jopapa). Once installed, follow these steps to create the Azure Functions on your computer.

1. Open the command palette by pressing **F1**
1. Type and select **Azure Functions: Create New Project**
1. Choose **Browse** to find the folder to create the functions
1. Create a new folder in your project called _functions_
1. Select **TypeScript**
1. When prompted to create a function, select **Skip for Now**

Congratulations, you just created an Azure Function app!

> The Azure Functions app is what serves our routes.

Creating the function app in a _functions_ folder helps separate it from the Angular and Express apps in the same project. You certainly don't have to put them all in the same project together, but for this sample it helps to see them all in one place.

### Shifting Routes - Create Your First Function

You may recall that we have eight endpoints in the Express app. Follow these steps to create a function for the first of these endpoints. We'll come back and create the other seven endpoints soon.

1. Open the command palette by pressing **F1**
1. Type and select **Azure Functions: Create Function**
1. Choose **HTTP Trigger** for the type of function
1. Enter **heroes-get** as the name of the function
1. Select **Anonymous** for the authentication level

Notice that there is now a folder _functions/heroes-get_ that contains a few files. The _function.json_ contains the configuration for the function. Open _function.json_ and notice that the methods allow both GET and POST. Change this to only allow GET.

By default the route to execute this function will be **heroes-get**. The route in the Express app is simply **heroes**. We want these to be the same, so add a `route: "heroes"` entry in the **bindings** section in the _function.json_. Now the function will be executed when an HTTP GET on **/heroes** is called.

Your _function.json_ should look like the following code.

```json
{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get"],
      "route": "heroes"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ],
  "scriptFile": "../dist/heroes-get/index.js"
}
```

The other important file here in the _functions/heroes-get_ folder is _index.ts_. This file contains the logic that runs when the route is invoked. We already have all this logic from our Express app. We'll go get that next.

### Data - Shift the Services to Serverless

All of the logic that executes to interact with the data store is contained in the _server/services_ folder of the Express app. We can lift that code and shift it over to the Azure Functions app and make a few small adjustments. This may seem like it wouldn't work, but let's consider what is different about the Express app and the Azure Functions app. Here are some main differences in the services.

1. The Express app uses the npm package **express** while the Azure Functions app uses the npm package **@azure/functions**
2. Express has `req` and `res` parameters representing Request and Response. Azure Functions puts these inside of a `context` object variable.

That is all we have to know. So armed with this information, it makes sense that we can copy the code for the services from the Express app to the Azure Functions app with minimal changes. Let's do this now.

#### Shift the Code from Express to Functions

Why write everything from scratch and throw away your hard work if you do not have to, right? Well, we can take the services code from our Express app and copy it to our Azure Functions app.

1. Copy the **server/services** folder
1. Paste into the **functions** folder

Now we have some minor refactoring to make the code work with Azure Functions instead of Express. The one thing that changes here is that the routing API and how request and response are passed. Let's refactor for this API difference.

1. Open the **functions/services/hero.service.ts** file
1. Replace `import { Request, Response } from 'express';` with `import { Context } from '@azure/functions';`
1. Replace every instance of `(req: Request, res: Response)` with `({ req, res }: Context)`.

Your code will look like the following when you are done refactoring. Notice the places that changed are commented.

```typescript
// 👇 This was import { Request, Response } from 'express';
import { Context } from '@azure/functions';
import * as data from './data';

// 👇 This was async function getHeroes(req: Request, res: Response) {
async function getHeroes({ req, res }: Context) {
  try {
    const heroes = data.getHeroes();
    res.status(200).json(heroes);
  } catch (error) {
    res.status(500).send(error);
  }
}

// 👇 This was async function postHero(req: Request, res: Response) {
async function postHero({ req, res }: Context) {
  const hero = {
    id: undefined,
    name: req.body.name,
    description: req.body.description
  };

  try {
    const newHero = data.addHero(hero);
    res.status(201).json(newHero);
  } catch (error) {
    res.status(500).send(error);
  }
}

// 👇 This was async function putHero(req: Request, res: Response) {
async function putHero({ req, res }: Context) {
  const hero = {
    id: req.params.id,
    name: req.body.name,
    description: req.body.description
  };

  try {
    const updatedHero = data.updateHero(hero);
    res.status(200).json(updatedHero);
  } catch (error) {
    res.status(500).send(error);
  }
}

// 👇 This was async function deleteHero(req: Request, res: Response) {
async function deleteHero({ req, res }: Context) {
  const { id } = req.params;

  try {
    data.deleteHero(id);
    res.status(200).json({});
  } catch (error) {
    res.status(500).send(error);
  }
}

export default { getHeroes, postHero, putHero, deleteHero };
```

There are four functions where request and response are parameters. One each for `getHeroes`, `postHero`, `putHero`, and `deleteHero`.

The parameters to every function in the Express app contain `req` and `res`. The Azure Functions app can still get to the request and response objects, but they are contained within a `context` object. We use destructuring to access them.

> The `Context` object also contains other APIs, such as `log` (ex: `context.log('hello')`). This could be used in place of the common `console.log` you use in Node apps.

#### Refactor the Route

Now point your route to the service in your **functions/heroes-get/index.ts** file. Open that file and replace it with the following code.

```typescript
import { AzureFunction, Context, HttpRequest } from '@azure/functions';
import { heroService } from '../services';

const httpTrigger: AzureFunction = async function(context: Context, req: HttpRequest): Promise<void> {
  await heroService.getHeroes(context); // 👈 This calls the hero service
};

export default httpTrigger;
```

The code that you add calls the asynchronous function `heroService.getHeroes` and passes in the `context` which contain the request and response objects.

### Create the Remaining Functions

Remember, there are eight total endpoints in the Express app and we just created the first one. Now, follow these steps to create an Azure Function for the rest of the endpoints.

1. Open the command palette by pressing **F1**
1. Type and select **Azure Functions: Create Function**
1. Choose **HTTP Trigger** for the type of function
1. Enter the name of the function for heroes and villains. I recommend **heroes-get**, **heroes-post**, **heroes-put**, **heroes-delete**, **villains-get**, **villains-post**, **villains-put**, **villains-delete**)
1. Select **Anonymous** for the authentication level
1. Open _function.json_ and set the method to the appropriate value of get, post, put or delete.
1. In the bindings section, for the **get** and **post**, add a `route: "heroes"` (or villains as appropriate) entry.
1. In the bindings section, for the **delete** and **put**, add a `route: "heroes/{id}"` (or villains as appropriate) entry.
1. Add the code in each function's _index.ts_ file to call the appropriate hero or villain service function.

### Looking at the Functions App

The Azure Functions app now has folders that map to their appropriate endpoints as shown below.

| method | route endpoint | folder          |
| ------ | -------------- | --------------- |
| GET    | heroes         | heroes-get      |
| POST   | heroes         | heroes-post     |
| PUT    | heroes:id      | heroes-put      |
| DELETE | heroes/:id     | heroes-delete   |
| GET    | villains       | villains-get    |
| POST   | villains       | villains-post   |
| PUT    | villains:id    | villains-put    |
| DELETE | villains/:id   | villains-delete |

The structure of the Azure Function app contained in the _functions_ folder should look like the following.

```text
functions
 | - heroes-delete
 | | - function.json
 | | - index.ts
 | - heroes-get
 | | - function.json  👈 The hero route's configuration
 | | - index.ts       👈 The hero routes
 | - heroes-post
 | | - function.json
 | | - index.ts
 | - heroes-put
 | | - function.json
 | | - index.ts
 | - services          👈 The same folder that the Express app has
 | | - data.ts         👈 The hero data (could be database API calls)
 | | - hero.service.ts 👈 The logic to get the hero data
 | | - index.ts
 | | - villain.service.ts
 | - villains-delete
 | | - function.json
 | | - index.ts
 | - villains-get
 | | - function.json
 | | - index.ts
 | - villains-post
 | | - function.json
 | | - index.ts
 | - villains-put
 | | - function.json
 | | - index.ts
 | - .funcignore
 | - .gitignore
 | - host.json
 | - local.settings.json
 | - package.json
 | - proxies.json
 | - tsconfig.json
```

## Debug Node Express and Angular

Now it's time to run the app and see if it all works! We'll do this through the VS Code debugger.

> Just to keep things separate, we'll make sure the Express app uses port **7070** and the Azure Functions app uses port **7071**. If we were truly removing the Express app (which we could absolutely do at this point) we could keep the same port. But for educational purposes, let's keep them both around

1. Open _proxy.conf.json_ and change the port to **7071** (our function app)
1. Open the VS Code Command Palette **F1**
1. Type **View: Show Debug** and press **ENTER**
1. Select **Debug Functions and Angular**
1. Press **F5**
1. Open the browser to <http://localhost:7071>

You may now set breakpoints in the Functions and Angular code.

![Debugging Azure Functions](https://thepracticaldev.s3.amazonaws.com/i/2l27psjcsqyh8f2u32ls.jpg)

> In case you missed it - the files _.vscode/launch.json_ and _.vscode/tasks.json_ are integral to the debugging experience for this project. I encourage you to explore those files and copy/refactor their contents for your own purposes.

## Optional - Remove the Express App

At this point the Express app is no longer being used. Feel free to delete it (you can always re-clone the GitHub sample) or keep it around if you want to go back and froth between Express and Azure Functions.

## Summary

The end result is we have Angular and Azure Functions. Now we can think about servers less (get it, because we are using serverless?).

Node and Express have been incredibly powerful and oft used for serving API endpoints. Now with serverless you could shift your APIs and not worry about server setup or maintenance, possibly reduce cost of an always on server, and replace the Express server with Azure Functions service. And for your efforts, you get an API that scales well and lets you focus on the code, not the servers.

> If you want to deploy the Azure Functions app to the cloud, you can [deploy it by following this tutorial](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions&WT.mc_id=devto-blog-jopapa). All you need is an [Azure account](https://azure.microsoft.com/en-us/free/?wt.mc_id=devto-blog-jopapa) and then use the Azure Functions extension for Visual Studio Code to deploy it.

The complete solution for the [sample project is on GitHub here](https://github.com/johnpapa/express-to-functions). The instructions on how to get started are also in the README file. You can explore running the Express app or the Azure Functions app to get a sense of the differences. Then try to apply this same shift to your code.

## Resources

Here are a bunch of resources about the topics covered in this article.

- [Azure Free Trial](https://azure.microsoft.com/en-us/free/?wt.mc_id=devto-blog-jopapa)

### VS Code

- [VS Code](https://code.visualstudio.com?wt.mc_id=devto-blog-jopapa)
- [VS Code Extension for Node on Azure](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack&WT.mc_id=devto-blog-jopapa)
- [VS Code Extension for Azure Functions](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions&WT.mc_id=devto-blog-jopapa)

### Azure Functions

- Azure Functions [local.settings.json](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#local-settings-file?WT.mc_id=devto-blog-jopapa) file
- Tutorial to [Deploy to Azure Using Azure Functions](https://code.visualstudio.com/tutorials/functions-extension/getting-started?WT.mc_id=devto-blog-jopapa)
- Article about [Azure Functions TypeScript Support](https://azure.microsoft.com/en-us/blog/improving-the-typescript-support-in-azure-functions/?WT.mc_id=devto-blog-jopapa)

### Debugging Resources

- [Debugging Angular in VS Code](https://code.visualstudio.com/docs/nodejs/angular-tutorial?wt.mc_id=devto-blog-jopapa)
- [Debugging React in VS Code](https://code.visualstudio.com/docs/nodejs/reactjs-tutorial?wt.mc_id=devto-blog-jopapa)
- [Debugging Vue in VS Code](https://code.visualstudio.com/docs/nodejs/vuejs-tutorial?wt.mc_id=devto-blog-jopapa)
- [Tasks in VS Code](https://code.visualstudio.com/Docs/editor/tasks?wt.mc_id=devto-blog-jopapa)