Setting up Express and Redis with Docker Compose
Tags: javascript, docker, express, redis
Published: 2018-06-06 14:01:14

---
title: Setting up Express and Redis with Docker Compose
published: true
tags: JavaScript,Docker,express,redis
canonical_url: https://codewithhugo.com/setting-up-express-and-redis-with-docker-compose/
cover_image: https://codewithhugo.com/img/ben-koorengevel-unsplash.jpg
---
Redis and Express are tools that provide a simple and clean approach to their problem domains.

The repo is available at: https://github.com/HugoDF/express-redis-docker.

[Redis](https://redis.io/) is “an open source, in-memory data structure store, used as a database, cache and message broker”. It’s as simple and unopinionated as a database as it gets, it’s known for its performance and simplicity as a key-value store. It has great flexibility and can also be used as a message queue, circular buffer (and pretty much anything else a developer can come up with short of a relational database).

[Express](https://expressjs.com/) is a “fast, unopinionated, minimalist web framework for Node.js”. In other words, it’s a wrapper around Node’s server, that provides a way to write what’s called “middleware” to share and compose functionality across HTTP endpoints as well as define said endpoints.

Getting Redis and Express to work together is trivial. Getting Redis and Express to work together in a way that’s fool and future-proof, and reproducible across local and deployed environments, is slightly harder. That’s where Docker and Docker Compose come in.

Docker is a containerisation system, Docker Compose is a way to define how multiple Docker containers interact. In the context of Node web application development, Docker tends to be used to define a container that has the required system-level dependencies (eg. Node version, any extra database drivers). Docker Compose would be used to define dependencies outside of the Node application, for example databases.

- [Initialising Express 🚅](https://codewithhugo.com/setting-up-express-and-redis-with-docker-compose#initialising-express)
- [Running Node inside of Docker 🌊](https://codewithhugo.com/setting-up-express-and-redis-with-docker-compose#running-node-inside-of-docker)
- [Adding Redis](https://codewithhugo.com/setting-up-express-and-redis-with-docker-compose#adding-redis)
- [Creating a blob store 📒](https://codewithhugo.com/setting-up-express-and-redis-with-docker-compose/#creating-a-blob-store)

[Subscribe](https://buttondown.email/hugo) to get the latest posts right in your inbox (before anyone else).


# Initialising Express 🚅

To start off, we should create a new directory/initialise npm: 

```sh
mkdir express-redis
cd express-redis
npm init -y
```

We can then install Express:

```sh
npm i --save express
```

And create a `server.js` file that looks like the following:
```js
// server.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    return res.send('Hello world');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server listening on port ${PORT}`);
});
```

That can be run using:
```sh
node server.js
```

We can check that it’s working as expected

```sh
curl http://localhost:3000/
Hello world
```

# Running Node inside of Docker 🌊

To begin you’ll want to install [Docker Community Edition](https://www.docker.com/community-edition) ([https://www.docker.com/community-edition](https://www.docker.com/community-edition)).
Then we can add a `Dockerfile` and a `docker-compose.yml`:

```dockerfile
# Dockerfile
FROM node:9-alpine
# Or whatever Node version/image you want
WORKDIR '/var/www/app'
```

```yml
# docker-compose.yml
app:
    build: ./
    volumes:
    - ./:/var/www/app
    ports:
    - 3000:3000
    environment:
    - NODE_ENV=development
    - PORT=3000
    command:
    sh -c 'npm i && node server.js'
```

Now run the app inside of Docker/Docker Compose:

```sh
docker-compose up
```

And check that it still works

```sh
curl http://localhost:3000/
Hello world
```

Some extra context:

- The `Dockerfile` defines what container the application will be running in (here a Node 9 container built on top of alpine)
- `docker-compose.yml`:
  - `build` explains which image should be used by the `app` service definition (in this case, it points to what would be created by running the `Dockerfile`)
  - `volumes` defines what should be mounted where (in this case, we’ll mount the whole directory as `/var/www/app`
  - `ports` maps ports from the host system to ports inside the container
  - `environment` sets environment variables for the container
  - `command` determines what will be run on startup of the container, here it runs `npm install` followed by the server startup command

# Adding Redis 

To add Redis to our Express app we should use the `redis` package:
```sh
npm install --save redis
```

Then we should probably wrap all the callback-based methods we want to use (see the api docs for the redis package, https://github.com/NodeRedis/node_redis#api).
Let’s do this using a `redis-client.js` module:
```js
// redis-client.js
const redis = require('redis');
const {promisify} = require('util');
const client = redis.createClient(process.env.REDIS_URL);

module.exports = {
  ...client,
  getAsync: promisify(client.get).bind(client),
  setAsync: promisify(client.set).bind(client),
  keysAsync: promisify(client.keys).bind(client)
};
```

To running Redis inside of Docker Compose in such a way that our app can access it:

```yml
# docker-compose.yml
# Add this top-level entry
redis:
    image: redis
    container_name: cache
    expose:
    - 6379
    
app:
    # some definitions
    links:
    - redis
    environment:
    - REDIS_URL=redis://cache
    # rest of the environment definitions
```

We can now access the Redis client from the app container:

```sh
docker-compose run app node
> require('./redis-client') // doesn't crash
```


# Creating a blob store 📒

We can now create a HTTP API that will allow us to store data using query params and retrieve them using a get request (this isn’t RESTful at all but oh well 🙂 ).

```js
// server.js
// imports and app definition

const redisClient = require('./redis-client');
app.get('/store/:key', async (req, res) => {
    const { key } = req.params;
    const value = req.query;
    await redisClient.setAsync(key, JSON.stringify(value));
    return res.send('Success');
});
app.get('/:key', async (req, res) => {
    const { key } = req.params;
    const rawData = await redisClient.getAsync(key);
    return res.json(JSON.parse(rawData));
});

// code that starts the app...
```

If you have any questions about the above code let me know [@hugo__df](https://twitter.com/hugo__df). It is using a couple of more advanced features like async/await and destructuring as well as Express features to get query and path parameters (see [https://expressjs.com/en/api.html#req.query](https://expressjs.com/en/api.html#req.query), https://expressjs.com/en/api.html#req.params).

Get the app running again: `docker-compose up`

1. Store some data
```sh
curl http://localhost:3000/store/my-key\?some\=value\&some-other\=other-value
Success
```
2. Retrieve that data:
```sh
curl http://localhost:3000/my-key
{
    "some": "value",
    "some-other": "other-value"
}
```


> Note to more advanced Express users, and API design gurus. 
> The reason I used an old school query-param based system is to avoid the boilerplate of using `body-parser` with POST requests

Full repository available at: https://github.com/HugoDF/express-redis-docker


[Subscribe](https://buttondown.email/hugo) to get the latest posts right in your inbox (before anyone else).
Cover photo by [Ben Koorengevel](https://unsplash.com/photos/rpMwfGLSsd8?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/boats?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)