Build a Simple REST API with Node and Postgres
Tags: code, featureflags, node
Published: 2021-02-06 01:56:33

---
title: Build a Simple REST API with Node and Postgres
published: true
date: 2020-11-18 15:30:00 UTC
tags: Code,featureflags,node,nodejs
canonical_url: https://www.split.io/blog/rest-api-node-postgres/
---

Creating a server that stores data in the database and responds to user requests through a RESTful API doesn’t need to be scary or time-consuming. In this tutorial I’ll walk you through the process using the popular combination of a JavaScript-driven Node.js server-side environment and a Postgres database.

Over the course of the post, you’ll:

- Create a server-side application with Node and Express that works with mocked in-memory data
- Create a Postgres database to persist data as a new feature of your app
- Deploy the database feature to a specific portion of users with [feature flags](https://www.split.io/blog/branch-by-abstraction/) by Split
- Test how the application works with multiple branching scenarios
- Completely migrate the app to the new database once testing is complete

Hopefully, you’ll have some fun along the way, as the example app you’re going to build will store a database of scary horror movies and their ratings!

## Node, Express, and Postgres Prerequisites

To build along, you’ll need Node.js and npm installed and a forever-free [Split](https://app.split.io/) account. Simple!

The next sections will walk you through creating your Node.js app from scratch. The full code example is available in this [splitio-examples GitHub repo](https://github.com/splitio-examples/split-nodejs-postgres-example) if you want to follow along that way as well.

## Set Up the Express Server

Start by creating a project directory and navigate to its root folder:

```

`mkdir node-postgres
cd node-postgres`
<small id="shcb-language-60"><span>Code language:</span> <span>Bash</span> <span>(</span><span>bash</span><span>)</span></small>
```

Initialize `npm` in the project by running `npm init`, which will create a `package.json` file. Alternatively, you can copy this JSON structure to a `package.json` that you make on your own:

```

`{
  "name": "node-postgres-api",
  "version": "1.0.0",
  "description": "RESTful API with Node.js, Express, and PostgreSQL",
  "main": "app.js",
  "scripts": {}
}`
<small id="shcb-language-61"><span>Code language:</span> <span>JSON / JSON with Comments</span> <span>(</span><span>json</span><span>)</span></small>
```

The next thing you need is to install Express.js.

```

`npm i express`
<small id="shcb-language-62"><span>Code language:</span> <span>Matlab</span> <span>(</span><span>matlab</span><span>)</span></small>
```

Create an `app.js` file where the server application will run:

```

`const express = require('express');
const app = express();
const port = 5000;

app.use(express.json());

app.listen(port, () => {
  console.log(`Horror movie app is running on port ${port}.`);
});`
<small id="shcb-language-63"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

The Express module is required to create a server, and the line containing `app.use(express.json())` is utilizing middleware for parsing the requests that you’ll be sending later in this tutorial. Note that the server is running on port `5000`, meaning that the base URL where the application runs is `http://localhost:5000`.

At this point, it would be good to install the utility package Nodemon, which will speed up your development by automatically restarting the server after each change. Nodemon is installed as a development dependency.

```

`npm i nodemon -D`
<small id="shcb-language-64"><span>Code language:</span> <span>Matlab</span> <span>(</span><span>matlab</span><span>)</span></small>
```

In the `package.json` file, inside the `scripts` property, add a script named `serve` with the `nodemon app.js` command, which will start the server.

```

`...
"scripts": {
    "serve": "nodemon app.js"
  }
...`
<small id="shcb-language-65"><span>Code language:</span> <span>Bash</span> <span>(</span><span>bash</span><span>)</span></small>
```

Now you can start your server by simply running:

```

`npm run serve`
<small id="shcb-language-66"><span>Code language:</span> <span>Arduino</span> <span>(</span><span>arduino</span><span>)</span></small>
```

What you should see in the command line is this:

![Nodemon restarts our node and postgres REST API server after any change](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-nodemon-launch-app-js.png?width=762)

Without Nodemon, you can always run your app directly by `node app.js`.

## What’s a Server without Endpoints?

You’ll agree that running a server just for the sake of it doesn’t make much of a difference in this world. So you’ll want to add some endpoints (routes) to it. Say you’re a big movie fan, and you want to list your favorite horror movies by rating. Of course, over time you’ll need to add new horror movies to the list? Maybe change or even delete some? It’s always a good idea to make a model of all the endpoints youcan imagine you’ll need:

- `GET /horrors` – fetch all horror movies
- `GET /horrors/:id` – fetch a single horror movie by its ID
- `POST /horrors` – create a new horror movie entry
- `PUT /horrors/:id` – update a existing horror horror movie entry
- `DELETE /horrors/:id` – delete a horror movie

These endpoints are integrated into the `app.js` server file in no time, but there needs to be some logic behind them, as every endpoint has to return a specific response to the user. With that in mind, the next file to create is `api.js`, where that logic is implemented. In the first iteration, the server will work only with a hardcoded list of horror movies that is persisted only in memory while the application runs. Once the server is restarted, the horror movie list will be reset to the initial state.

| You probably agree that having a hardcoded list of data can be a quick and dirty solution for an ad-hoc prototype, but eventually, you’ll want to change the in-memory data with the persisted one – a database. And that’s exactly what you do later, in a gradual, safe, feature flag driven fashion. |

This is the hardcoded list of horror movies you’ll use as a starting point inside `api.js`:

```

`const inMemoryHorrors = [
  {
    name: 'The Hills Have Eyes',
    rating: 7.8
  },
  {
    name: 'Night of the Living Dead',
    rating: 9.0
  },
  {
    name: 'Scream',
    rating: 7.2
  }
];`
<small id="shcb-language-67"><span>Code language:</span> <span>C#</span> <span>(</span><span>cs</span><span>)</span></small>
```

The function to get all the horror movies will just return that list:

```

`const getAllHorrors = async (request, response) => {
  response.status(200).json(inMemoryHorrors);
};`
<small id="shcb-language-68"><span>Code language:</span> <span>C#</span> <span>(</span><span>cs</span><span>)</span></small>
```

Request for a single horror movie will always return the first one from the list, no matter what `id` is provided:

```

`const getHorrorById = (request, response) => {
  response.status(200).json(inMemoryHorrors[0]);
};`
<small id="shcb-language-69"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

The other CRUD endpoints are also aligned with the in-memory list. The creation of a new horror movie adds a new item to the list. An update always makes changes to the first list item, and delete always removes the first horror movie in the list. You’re probably thinking: _not too clever_, and you’re absolutely right, but remember, it’s just a starting mockup of your app. The intent is that it’s just enough to navigate the initial development cycle, prototype presentation phase, and numerous design tweaks at the very start.

```

`const addHorror = async (request, response) => {
  const { name, rating } = request.body;
  inMemoryHorrors.push({ name, rating });
  response.status(201).send(`Horror added successfully.`);
};

const updateHorror = (request, response) => {
  const { name, rating } = request.body;
  inMemoryHorrors[0] = { name, rating };
  response.status(200).send(`First horror in list is updated.`);
};

const deleteHorror = (request, response) => {
  inMemoryHorrors.shift();
  response.status(200).send(`First horror in list is deleted.`);
};`
<small id="shcb-language-70"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

## Put Your Node Server Together

All these functions need to be exported from the `api.js` file to be consumed outside of it. So you should write down everything you’re exposing from this file with `module.exports` syntax, which is part of the `CommonJS` module system, essential for Node.js environments.

```

`module.exports = {
  getAllHorrors,
  getHorrorById,
  addHorror,
  updateHorror,
  deleteHorror
};`
<small id="shcb-language-71"><span>Code language:</span> <span>Java</span> <span>(</span><span>java</span><span>)</span></small>
```

This completes `api.js`.

Great! You have now written down all the functions that perform operations inside the database and exported them. Unfortunately, this still doesn’t do much for your app, as those functions are not being used just yet. But, now, you’ll connect them with the server in a simple way. In the `app.js` add the following lines:

```

`const api = require('./api');

app.get('/horrors/', api.getAllHorrors);
app.get('/horrors/:id', api.getHorrorById);
app.post('/horrors/', api.addHorror);
app.put('/horrors/:id', api.updateHorror);
app.delete('/horrors/:id', api.deleteHorror);`
<small id="shcb-language-72"><span>Code language:</span> <span>C#</span> <span>(</span><span>cs</span><span>)</span></small>
```

This effectively creates five endpoints inside the Express server. When an HTTP request comes to your server, its URL and HTTP methods are matched against the configured endpoints on the server. If the URL (the first parameter in the `get`, `post`, `put` and `delete` methods of the `app` object above) and HTTP method match a specific route configuration, then a function (i.e., a middleware, the second parameter) runs.

Appropriately configured, the API should always return some kind of a response, either the resource that is requested, usually along with `HTTP 2xx` status or some other kind of response, like error (`4xx` and `5xx`) or redirect(`3xx`).

Finally, the mock server can be easily tested with curl. Running this line in your terminal should return the initial list of horror movies:

```

`curl http://localhost:5000/horrors`
<small id="shcb-language-73"><span>Code language:</span> <span>Arduino</span> <span>(</span><span>arduino</span><span>)</span></small>
```

Feel free to experiment with other endpoints, and bear in mind it will all get reset once you restart the server.

## Create a Local Database with Postgres

Having a mock server is nice, but eventually, you’ll want your app to store the data after it stops running. You’ll want to set up a database and then connect it to your app. Sounds complicated? Well, it isn’t, thanks to Postgres.

PostgreSQL is an open-source relational database management system. Postgres has been around for more than two decades, and it is a trusted choice in the database market, popular equally among freelance developers and enterprises.

If you are a Windows user, you can find the installation guide for Postgres [here](https://www.postgresql.org/download/windows/). Mac users that have Homebrew installed can simply install Postgres from the terminal. If you don’t have Homebrew, take a look [here](https://brew.sh/) for how to install it.

```

`brew install postgresql`
<small id="shcb-language-74"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

What you’ve installed here, among other things, is a database server. That is a service that can be started (or stopped) with Homebrew. The following line starts the database server from the terminal:

```

`brew services start postgresql
==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql)`
<small id="shcb-language-75"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

At any point, the database server can be stopped with `brew services stop postgresql`.

Another thing that comes with the installation is the _psql_ – PostgreSQL interactive terminal. Running `psql` will connect you to a PostgreSQL host from the terminal and allow you to perform database operations from the command line. When you install Postgres, you get one default database named – `postgres`. So you’ll first connect to it via `psql`:

```

`psql postgres`

```

You are now _inside_ `psql` in the `postgres` database. You should see the text below in your terminal now, which means you’re connected to the `postgres` database as _superuser_, or root (the `#` mark is for superuser).

```

`postgres=#`
<small id="shcb-language-76"><span>Code language:</span> <span>Bash</span> <span>(</span><span>bash</span><span>)</span></small>
```

But, you won’t use the default database or any database as a superuser. You’ll create your user and database, and it’s not all that complicated. Start with creating your own _role_ `moviefan` with a password `scarymovie`.

```

`CREATE ROLE moviefan WITH LOGIN PASSWORD 'scarymovie';`
<small id="shcb-language-77"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

Don’t get confused by “role” here. In the Postgres world, `role` is a superset concept that wraps both users and groups. To put it simply, you’re using it here to create a user. Also, the new user that you’ve made needs some access rights. You want your user to be able to create a database.

```

`ALTER ROLE moviefan CREATEDB;`
<small id="shcb-language-78"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

Check if you’ve done everything in order, you can list all users by `\du`. Just note that, if installed on a Mac OS with Homebrew, the role name for the Postgres superuser will be the same as the name of the logged-in user that installed it. In Linux systems, it would default to `postgres`.

| Role name | Attributes | Member of |
| --- | --- | --- |
| <your username> | Superuser, Create role, Create DB, Replication, Bypass RLS | {} |
| moviefan | Create DB | {} |

Your work with superuser privileges is done here. You now proceed using the `psql` as `moviefan` user. But before that, you need to quit the terminal as a superuser with `\q`.

Now you are again outside of the `psql` terminal and in your “regular” one. You can connect to the `postgres` database with the `moviefan` user now:

```

`psql -d postgres -U moviefan`

```

The terminal now shows `postgres=>`, which is an indicator of not being logged in as a superuser anymore. The next thing in line is to create a database.

```

`CREATE DATABASE movies;`
<small id="shcb-language-79"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

Then, connect to the newly created `movies` database using the `\c` (connect) command.

```

`\c movies
You are now connected to the database “movies” as user “moviefan”.`
<small id="shcb-language-80"><span>Code language:</span> <span>Delphi</span> <span>(</span><span>delphi</span><span>)</span></small>
```

Before switching back to Node, let’s create a table in the newly formed database. You’ll create a table `horrors` with three fields: `name` field of `varchar` type, `rating` field of `decimal` type, and an `id` field, which is a primary key.

```

`CREATE TABLE horrors (
  ID SERIAL PRIMARY KEY,
  name VARCHAR(40),
  rating DECIMAL
);`
<small id="shcb-language-81"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

Also, the table can be populated with some initial data.

```

`INSERT INTO horrors (name, rating)
  VALUES ('The Ring', 8.6), ('The Exorcist', 8.8), ('The Nightmare On Elm Street', 8.2);`
<small id="shcb-language-82"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

Finally, check on the created data with a select statement.

```

`SELECT * FROM horrors;
 id | name | rating 
----+-----------------------------+--------
  1 | The Ring | 8.6
  2 | The Exorcist | 8.8
  3 | The Nightmare On Elm Street | 8.2`
<small id="shcb-language-83"><span>Code language:</span> <span>Gherkin</span> <span>(</span><span>gherkin</span><span>)</span></small>
```

## Node + Feature Flags

Feature flags are an excellent tool for delivering your app’s features to a specific portion of your audience. Let’s say you have a new feature coming up, but you’re still not ready to let it go into the wild. In other words, you want your QA team to get the taste of this new feature first.

Inside this tutorial, the new feature will be the database that you’ll soon connect with the server, and, at first, expose it only to the users behind a `qa@movies.com` email. To create a feature flag, you’ll need access to [Split](https://app.split.io/) application. If you don’t have a free Split account yet, you’ll need to sign up now.

After you log in to Split, navigate to the **Splits** section on the left, and click **Create Split**. The dialog will prompt you for the split’s name, which you can define as `database_split`. Leave the default settings for everything else, and you’re good to go. Click **Create** to finish.

![](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-create-a-split-1024x979.png?width=1024)

After successful creation, this is what you’ll see:

![](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-split-add-rules.png?width=892)

To configure the split settings, click **Add Rules**.

Possible states of feature flags in Split are called _treatments_. The most common values for treatments are `on` or `off`, but you can use any other value. In your case, when the treatment is `on`, the routes that the user hits will connect to the database, and if it’s `off` they’ll return the initial (mocked) state of the running application.

![](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-define-treatments-1024x249.png?width=1024)

The next thing to set up are the _targeting rules_, where you’ll define who will be targeted inside your feature flag. As shown in the picture, this configuration will get the `on` treatment for all users that represent themselves as `qa@movies.com`. Everybody else will get the `off` treatment, configured in the **Set The Default Rule** section.

| If, for some reason, your split isn’t active in the application at all, users will branch according to what you’ve set up inside the **Set The Default Treatment** section. A good practice is to have `off` treatment as the default one, as you don’t want untested features to accidentally be made accessible. |

![](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-set-targeting-rules-1024x457.png?width=1024)

Click **Save changes** , and then **Confirm** , to save your settings in Split.

To use feature flags in your Node.js application, Split’s Node.js SDK is required. It can be installed via npm:

```

`npm i @splitsoftware/splitio`
<small id="shcb-language-84"><span>Code language:</span> <span>CSS</span> <span>(</span><span>css</span><span>)</span></small>
```

Add the following code in the `app.js`:

```

`const SplitFactory = require('@splitsoftware/splitio').SplitFactory;

const factory = SplitFactory({
  core: {
    authorizationKey: 'YOUR_API_KEY'
  }
});

const client = factory.client();`
<small id="shcb-language-85"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

Note that the API key to use here is the one you can see in the **Admin Settings** of the Split dashboard, as pictured below. The key you’ll search for is a staging one for the SDK, the second one from the list on the image below. Of course, it would be good to store this API key inside an environment variable in a production app.

![](https://www.split.io/wp-content/uploads/2020/11/nodepostgres-split-admin-settings-1024x429.png?width=1024)

With the SDK plugged in, you can utilize it to get a respective treatment for a user’s request through an exposed method called `getTreatment`. Inside `app.js`, you’ll write a function named `treatmentMiddleware` that calculates the treatment using `getTreatment`, by passing the user’s email to it. Email is read from the `authorization` header that comes with every request and then evaluated in the context of a targeting rule you previously configured inside the Split app. Note how the second argument of the `getTreatment` method is your split’s name (`database_split`).

```

`const treatmentMiddleware = function (request, response, next) {
  const userEmail = request.headers['authorization'];
  request.treatment = client.getTreatment(userEmail, 'database_split');
  next();
};`
<small id="shcb-language-86"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

The purpose of the `treatmentMiddleware` is to put the treatment on the `request` object and proceed to the next middleware, which is the endpoint function defined inside `api.js`, by `next()` invocation. This is how the routing now looks, with a new middleware added:

```

`app.get('/horrors/', treatmentMiddleware, api.getAllHorrors);
app.get('/horrors/:id', treatmentMiddleware, api.getHorrorById);
app.post('/horrors/', treatmentMiddleware, api.addHorror);
app.put('/horrors/:id', treatmentMiddleware, api.updateHorror);
app.delete('/horrors/:id', treatmentMiddleware, api.deleteHorror);`
<small id="shcb-language-87"><span>Code language:</span> <span>C#</span> <span>(</span><span>cs</span><span>)</span></small>
```

| For a production app, you’d want to have some kind of authentication mechanism to identify your users, but here we are just sending the user’s email as the `authorization` header of each request. |

Now it’s time to connect to a database and use this treatment logic for branching.

## Postgres, Meet Node

With the local database working properly, it’s time to wire up your app. What comes in handy here is the `node-postgres` package or `pg`, which provides a communication layer to Postgres databases from the Node environment. It’s installed via npm, from the root project directory:

```

`npm i pg`
<small id="shcb-language-88"><span>Code language:</span> <span>Matlab</span> <span>(</span><span>matlab</span><span>)</span></small>
```

The Node.js application isn’t aware of a database existing in the system or a database server running on your machine unless you provide connection data with credentials. In the `api.js` you can set that exact configuration at the top:

```

`const Pool = require('pg').Pool;

const pool = new Pool({
  user: 'moviefan',
  host: 'localhost',
  database: 'movies',
  password: 'password',
  port: 5432
});`
<small id="shcb-language-89"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

`pg` exposes a database connection `Pool` class. A new instance of the class, or new connection, if you will, is created by passing the configuration object to its constructor. Here you’ll recognize the data we’ve set recently, with `5432` being the default value for `port`. Now you’ll be able to use the connection pool instance to communicate with the database inside your endpoints.

| In a production-ready application, database credentials present a sensitive piece of data that you’d want to keep away from the source code and store instead on the server machine itself as environment variables. |

## Add Route Branching with Feature Flags

Let’s now rework your endpoints inside `api.js` to have different branches, i.e., _different responses according to the treatment the user is getting_. If a user gets an `on` treatment, `getAllHorrors` will now return all the horror movies from the database, sorted by rating and in ascending order. And for all other cases (either an `off` treatment or no split in play at all), it will return the hardcoded data as before.

```

`const getAllHorrors = async (request, response) => {
    if (request.treatment == 'on') {
      pool.query('SELECT * FROM horrors ORDER BY rating ASC', (error, results) => {
        response.status(200).json(results.rows);
      });
    } else {
      response.status(200).json(inMemoryHorrors);
    }
};`
<small id="shcb-language-90"><span>Code language:</span> <span>PHP</span> <span>(</span><span>php</span><span>)</span></small>
```

| The `query` method inside the `pool` object gives you the ability to utilize raw SQL, as seen here. Of course, raw SQL isn’t the only way to write your queries inside the Node.js ecosystem, as you can use query builders like Knex.js or an ORM like Sequelize. |

Similarly, you can rework all other endpoints with treatment dependent branching as well. Note that the `else if (request.treatment == 'off')` block is omitted, as the same response is sent if the treatment is `off`, but also if the treatment has any other value.

```

`const getHorrorById = (request, response) => {
    const id = parseInt(request.params.id);
    if (request.treatment == 'on') {
        pool.query('SELECT * FROM horrors WHERE id = $1', [id], (error, results) => {
            response.status(200).json(results.rows);
        });
    } else {
        response.status(200).json(inMemoryHorrors[0]);
    }
};

const addHorror = async (request, response) => {
    const { name, rating } = request.body;
    if (request.treatment == 'on') {
        pool.query('INSERT INTO horrors (name, rating) VALUES ($1, $2)', [name, rating], (error, results) => {
            response.status(201).send(`Horror added successfully.`);
        });
    } else {
        inMemoryHorrors.push({ name, rating });
        response.status(201).send(`Horror added successfully.`);
    }
};

const updateHorror = (request, response) => {
    const id = parseInt(request.params.id);
    const { name, rating } = request.body;

    if (request.treatment == 'on') {
        pool.query('UPDATE horrors SET name = $1, rating = $2 WHERE id = $3', [name, rating, id], (error, results) => {
            response.status(200).send(`Horror with id ${id} modified.`);
        });
    } else {
        inMemoryHorrors[0] = { name, rating };
        response.status(200).send(`Horror with id ${id} modified.`);
    }
};

const deleteHorror = (request, response) => {
    const id = parseInt(request.params.id);

    if (request.treatment == 'on') {
        pool.query('DELETE FROM horrors WHERE id = $1', [id], (error, results) => {
            response.status(200).send(`Horror with id ${id} deleted.`);
        });
    } else {
        inMemoryHorrors.shift();
        response.status(200).send(`Horror with id ${id} deleted.`);
    }
};`
<small id="shcb-language-91"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

You should now test all of these scenarios to ensure everything is put together correctly. Let’s try to fetch all our horror movies with curl. You’ll introduce yourself as `qa@movies.com` user by putting that email in the `authorization` header in the first attempt.

```

`curl http://localhost:5000/horrors -H "authorization:qa@movies.com"`
<small id="shcb-language-92"><span>Code language:</span> <span>Elixir</span> <span>(</span><span>elixir</span><span>)</span></small>
```

As this request hits the `on` treatment branch due to the given email in the header, here is the response that you should be getting if you populated the database with the same data as in the tutorial:

```

`[{"id":3,"name":"The Nightmare On Elm Street","rating":"8.2"},{"id":1,"name":"The Ring","rating":"8.6"},{"id":2,"name":"The Exorcist","rating":"8.8"}]`
<small id="shcb-language-93"><span>Code language:</span> <span>JSON / JSON with Comments</span> <span>(</span><span>json</span><span>)</span></small>
```

On the other hand, the same request without a header fetches you the hardcoded in-memory list of horror movies, as it targets the `off` treatment:

```

`curl http://localhost:5000/horrors`
<small id="shcb-language-94"><span>Code language:</span> <span>Arduino</span> <span>(</span><span>arduino</span><span>)</span></small>
```

Here is the example of the authorized create request, which adds a new horror movie to the database. `content-type` header also needs to be added to the request, as you send the body of `application/json` type.

```

`curl http://localhost:5000/horrors -d '{"name":"The Last House On The Left","rating":"5.6"}' -H "authorization:qa@movies.com" -H "content-type:application/json"`
<small id="shcb-language-95"><span>Code language:</span> <span>Gherkin</span> <span>(</span><span>gherkin</span><span>)</span></small>
```

And now, let’s hit the `getHorrorById` route, but with a slightly different header:

```

`curl http://localhost:5000/horrors/1 -H "authorization:user@movies.com"`
<small id="shcb-language-96"><span>Code language:</span> <span>Bash</span> <span>(</span><span>bash</span><span>)</span></small>
```

Note how this didn’t return the `The Ring` from the database (the one with the `id` of `1`), as it _didn’t hit the database_. It returned the first horror movie from your hardcoded list, as the email `user@movies.com` isn’t listed in the split’s targeting rule, resulting in `off` treatment. Up next, few more examples that hit update and delete endpoints, respectively, both branching inside the `on` treatment, thanks to expected authorization:

```

`curl -X PUT http://localhost:5000/horrors/1 -d '{"name":"The Ring","rating":"7.6"}' -H "authorization:qa@movies.com" -H "content-type:application/json"`
<small id="shcb-language-97"><span>Code language:</span> <span>Gherkin</span> <span>(</span><span>gherkin</span><span>)</span></small>


`curl -X DELETE http://localhost:5000/horrors/1 -H "authorization:qa@movies.com"`
<small id="shcb-language-98"><span>Code language:</span> <span>SQL (Structured Query Language)</span> <span>(</span><span>sql</span><span>)</span></small>
```

So, this is your branching example right there, alive and kicking! Feel free to experiment with other requests as well, trying to hit both treatments, with curl or any other REST client.

### Extra Credit with PostgreSQL

You may have noticed that our hardcoded “database” has a float type value for the rating, but our PostgreSQL database returns a string type for the rating.

This is because the Postgres `numeric` type could be a larger value than will fit in a Javascript float.

But, we know that the rating maxes out at 10. So, you can set up a custom parser to ensure that the values get converted properly. Add this to the top of your `app.js` file:

```

`const types = require('pg').types

types.setTypeParser(1700, function(val) {
  return parseFloat(val)
});`
<small id="shcb-language-99"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

The `1700` is PostgreSQL type identifier for `numeric` type. Now, when you use curl to get all movies, you get a response where the ratings are floats again:

```

`curl http://localhost:5000/horrors -H "authorization:qa@movies.com"
[{"id":3,"name":"The Nightmare On Elm Street","rating":8.2},{"id":1,"name":"The Ring","rating":8.6},{"id":2,"name":"The Exorcist","rating":8.8}]`
<small id="shcb-language-100"><span>Code language:</span> <span>C#</span> <span>(</span><span>cs</span><span>)</span></small>
```

## Node and Postgres… Better with Feature Flags!

Feature flags just did for you what they’re made for – the ensured a safe transition to a new feature, without any risk of breaking anything. As you’re now sure that all endpoints work well with the database, there is no need to use the in-memory database anymore. As the last step, you can just delete all the parts directing requests to the _pre-database_ application state. That means there is no need to inspect the `request.treatment` value anymore, as all requests will be sent to the database. However, you can leave the Split initialization logic in the `app.js`, as it can be used for some future branching case. This is how the `api.js` file will look in the end:

```

`const Pool = require('pg').Pool;
const pool = new Pool({
  user: 'moviefan',
  host: 'localhost',
  database: 'movies',
  password: 'password',
  port: 5432
});

const getAllHorrors = async (request, response) => {
  pool.query('SELECT * FROM horrors ORDER BY rating ASC', (error, results) => {
    response.status(200).json(results.rows);
  });
};

const getHorrorById = (request, response) => {
  const id = parseInt(request.params.id);
  pool.query('SELECT * FROM horrors WHERE id = $1', [id], (error, results) => {
    response.status(200).json(results.rows);
  });
};

const addHorror = async (request, response) => {
  const { name, rating } = request.body;
  pool.query('INSERT INTO horrors (name, rating) VALUES ($1, $2)', [name, rating], (error, results) => {
    response.status(201).send(`Horror added successfully.`);
  });
};

const updateHorror = (request, response) => {
  const id = parseInt(request.params.id);
  const { name, rating } = request.body;
  pool.query(
    'UPDATE horrors SET name = $1, rating = $2 WHERE id = $3', [name, rating, id], (error, results) => {
      response.status(200).send(`Horror with id ${id} modified.`);
    }
  );
};

const deleteHorror = (request, response) => {
  const id = parseInt(request.params.id);
  pool.query('DELETE FROM horrors WHERE id = $1', [id], (error, results) => {
    response.status(200).send(`Horror with id ${id} deleted.`);
  });
};

module.exports = {
  getAllHorrors,
  getHorrorById,
  addHorror,
  updateHorror,
  deleteHorror
};`
<small id="shcb-language-101"><span>Code language:</span> <span>JavaScript</span> <span>(</span><span>javascript</span><span>)</span></small>
```

The Node Postgres example covered in this post is just one of the numerous ways to use feature flags inside the application’s development lifecycle. And in the real world, feature flags can [significantly improve](https://www.split.io/blog/continuous-deployment-feature-flags/) your deployment and delivery process.

## Learn More About Node, Feature Flags, and Testing in Production

Congrats, you made it through the end, and hopefully, a happy one, unlike in some of the movie titles we mentioned above. I’m glad I could help you learn something new about Node and Postgres and get a perspective on feature flags and how to use them. If you’d like to dive deeper on some of the topics and technologies covered in this post, I’d encourage you to check out these resources:

- [Testing a Feature-Flagged Change](https://split.io/blog/testing-feature-flagged-change/)
- [Migrate from Monolith to Microservices](https://split.io/blog/migrate-monolith-to-microservices/)
- [Get Started with Feature Flags in Node](https://split.io/blog/node-js-feature-flags/)
- [How to Implement Testing in Production](https://split.io/blog/how-to-implement-testing-in-production/)
- [7 Ways we Use Feature Flags Every Day at Split](https://split.io/blog/feature-flags-at-split/)

And as always, we’d love to have you follow along and catch all our latest content on [Twitter](https://twitter.com/SplitSoftware), [Facebook](https://www.facebook.com/splitsoftware), and [YouTube](https://www.youtube.com/channel/UCrkFMZZY8cjmZyKzOVV245Q/videos)!