Redis from Express

Using Redis from a Node.js Express App via Docker Compose

Updated: 03 September 2023

Setup Project

Init an NPM project with Redis and Express:

Terminal window
1
mkdir express-redis
2
cd express-redis
3
npm init -y
4
5
npm install express redis

Create Container

To start a Redis Container run:

Terminal window
1
docker run --name node-redis -p 6379:6379 -d redis redis-server --appendonly yes

Test A DB Query

The following code should create a key-value pair on redis, you can add this to a file called db.js

db.js

1
const redis = require('redis')
2
const client = redis.createClient()
3
4
client.on('error', function (error) {
5
console.error(error)
6
})
7
8
client.set('bob', 'i am bob', redis.print)
9
client.get('bob', redis.print)

Or, if you’re feeling that the default client is sketchy you can use this with the explicit url:

1
const client = redis.createClient({
2
url: ' redis://localhost:6379',
3
})

Either way, you can run this using node db.js which should output the creation success

View the Data from DB

You can login to the redis container via docker, and then from the command line you can log into the db itself with:

Terminal window
1
redis-cli

And then list all the keys using:

Terminal window
1
keys *

And we can even get the data from the DB using the get command:

Terminal window
1
get bob

Create an Express Client

A simple express client which will do key-value creates and lookups can be defined in an index.js file:

index.js

1
const express = require('express')
2
const redis = require('redis')
3
4
const port = process.env.PORT || 8080
5
6
const app = express()
7
8
app.use(express.text())
9
10
const client = redis.createClient({
11
url: 'redis://localhost:6379',
12
})
13
14
client.on('error', function (error) {
15
console.error(error)
16
})
17
18
app.get('/', (req, res) => {
19
console.log('request at URL')
20
res.send('hello nabeeel from port ' + port)
21
})
22
23
app.get('/:key', (req, res) => {
24
const key = req.params.key
25
client.get(key, (error, reply) => {
26
if (error) res.send('Error')
27
else res.send(reply)
28
})
29
})
30
31
app.post('/:key', (req, res) => {
32
const key = req.params.key
33
const data = req.body
34
client.set(key, data, (error, reply) => {
35
if (error) res.send('Error')
36
else res.send(reply)
37
})
38
})
39
40
app.posts
41
42
app.listen(port, () => {
43
console.log('app is listening on port ' + port)
44
})

You can then just run the web server with:

Terminal window
1
node index.js

The Dockerfile for the above app is so:

1
FROM node:14
2
3
COPY package.json .
4
COPY package-lock.json .
5
RUN npm ci
6
7
COPY . .
8
9
EXPOSE 8080
10
CMD ["npm", "start"]

Test the App

And you should then be able to make requests to the application from something like Postman for creating and retreiving a record

Set

With the server running you can create a new item with:

1
POST localhost:8080/my-test-key
2
3
BODY "my test data"
4
5
RESPONSE "OK"

Get

You can then get the value using the key with:

1
GET localhost:8080/my-test-key
2
3
RESPONSE "my test data"

Setting Up Compose

Before moving on please ensure you stop the Redis container we previously started with docker container stop node-redis

Since we’re using Docker, it would be great to configure our application using a Docker compose file. In the compose file we’ll define a web and redis service and will provide the Redis URL in the environment for our Express app, the service config for web is:

1
web:
2
image: express-app
3
build:
4
context: .
5
dockerfile: ./Dockerfile
6
environment:
7
NODE_ENV: production
8
REDIS_URL: redis://redis:6379
9
ports:
10
- 8080:8080

And for the redis service it’s pretty much the same as what we provided to the container we started with the command line:

1
redis:
2
image: redis
3
environment:
4
# ALLOW_EMPTY_PASSWORD is recommended only for development.
5
- ALLOW_EMPTY_PASSWORD=yes
6
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
7
ports:
8
- 6379:6379
9
volumes:
10
- .db:/data
11
restart: always
12
entrypoint: redis-server --appendonly yes

So the overall compose file will now be:

docker-compose.yml

1
version: '3.4'
2
3
services:
4
web:
5
image: express-app
6
build:
7
context: .
8
dockerfile: ./Dockerfile
9
environment:
10
NODE_ENV: production
11
REDIS_URL: redis://redis:6379
12
ports:
13
- 8080:8080
14
15
redis:
16
image: redis
17
environment:
18
# ALLOW_EMPTY_PASSWORD is recommended only for development.
19
- ALLOW_EMPTY_PASSWORD=yes
20
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
21
ports:
22
- 6379:6379
23
volumes:
24
- .db:/data
25
restart: always
26
entrypoint: redis-server --appendonly yes

Access Redis from Within Network

Now, it should be possible for us to access the redis instance using Service Discovery within the compose network, to do this we’ll use the REDIS_URL environment variable we defined above which will make a connection to redis://redis:6379 which will be resolved within the docker network that our application will run in

We can modify our client app by updating the connection to Redis as follows:

index.js

1
const redisUrl = process.env.REDIS_URL
2
3
// other stuff
4
5
const client = redis.createClient({
6
url: redisUrl,
7
})

So the final file will now be:

index.js

1
const express = require('express')
2
const redis = require('redis')
3
4
const port = process.env.PORT || 8080
5
const redisUrl = process.env.REDIS_URL
6
7
const app = express()
8
9
app.use(express.text())
10
11
const client = redis.createClient({
12
url: redisUrl,
13
})
14
15
client.on('error', function (error) {
16
console.error(error)
17
})
18
19
app.get('/', (req, res) => {
20
console.log('request at URL')
21
res.send('hello nabeeel from port ' + port)
22
})
23
24
app.get('/:key', (req, res) => {
25
const key = req.params.key
26
client.get(key, (error, reply) => {
27
if (error) res.send('Error')
28
else res.send(reply)
29
})
30
})
31
32
app.post('/:key', (req, res) => {
33
const key = req.params.key
34
const data = req.body
35
client.set(key, data, (error, reply) => {
36
if (error) res.send('Error')
37
else res.send(reply)
38
})
39
})
40
41
app.listen(port, () => {
42
console.log('app is listening on port ' + port)
43
})

And you should be able to run this all with:

Terminal window
1
docker-compose up

And this will run Redis as well as your Application, and you are pretty much good to use the application exactly as we did before addding the compose setup and will connect our application to Redis from within the docker network