Redis from Express
Using Redis from a Node.js Express App via Docker Compose
Setup Project
Init an NPM project with Redis and Express:
mkdir express-redis
cd express-redis
npm init -y
npm install express redis
Create Container
To start a Redis Container run:
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
const redis = require("redis");
const client = redis.createClient();
client.on("error", function(error) {
console.error(error);
});
client.set("bob", "i am bob", redis.print);
client.get("bob", redis.print);
Or, if you're feeling that the default client is sketchy you can use this with the explicit url:
const client = redis.createClient({
url: " redis://localhost:6379"
});
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:
redis-cli
And then list all the keys using:
keys *
And we can even get the data from the DB using the get
command:
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
const express = require('express')
const redis = require("redis");
const port = process.env.PORT || 8080
const app = express()
app.use(express.text())
const client = redis.createClient({
url: "redis://localhost:6379"
});
client.on("error", function(error) {
console.error(error);
});
app.get("/", (req, res) => {
console.log("request at URL")
res.send("hello nabeeel from port " + port)
})
app.get("/:key", (req, res) => {
const key = req.params.key
client.get(key, (error, reply) => {
if (error) res.send("Error")
else res.send(reply)
})
})
app.post("/:key", (req, res) => {
const key = req.params.key
const data = req.body
client.set(key, data, (error, reply) => {
if (error) res.send("Error")
else res.send(reply)
})
})
app.posts
app.listen(port, () => {
console.log("app is listening on port " + port)
})
You can then just run the web server with:
node index.js
The Dockerfile
for the above app is so:
FROM node:14
COPY package.json .
COPY package-lock.json .
RUN npm ci
COPY . .
EXPOSE 8080
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:
POST localhost:8080/my-test-key
BODY "my test data"
RESPONSE "OK"
Get
You can then get the value using the key with:
GET localhost:8080/my-test-key
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:
web:
image: express-app
build:
context: .
dockerfile: ./Dockerfile
environment:
NODE_ENV: production
REDIS_URL: redis://redis:6379
ports:
- 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:
redis:
image: redis
environment:
# ALLOW_EMPTY_PASSWORD is recommended only for development.
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
ports:
- 6379:6379
volumes:
- .db:/data
restart: always
entrypoint: redis-server --appendonly yes
So the overall compose file will now be:
docker-compose.yml
version: '3.4'
services:
web:
image: express-app
build:
context: .
dockerfile: ./Dockerfile
environment:
NODE_ENV: production
REDIS_URL: redis://redis:6379
ports:
- 8080:8080
redis:
image: redis
environment:
# ALLOW_EMPTY_PASSWORD is recommended only for development.
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
ports:
- 6379:6379
volumes:
- .db:/data
restart: always
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
const redisUrl = process.env.REDIS_URL
// other stuff
const client = redis.createClient({
url: redisUrl
});
So the final file will now be:
index.js
const express = require('express')
const redis = require("redis");
const port = process.env.PORT || 8080
const redisUrl = process.env.REDIS_URL
const app = express()
app.use(express.text())
const client = redis.createClient({
url: redisUrl
});
client.on("error", function(error) {
console.error(error);
});
app.get("/", (req, res) => {
console.log("request at URL")
res.send("hello nabeeel from port " + port)
})
app.get("/:key", (req, res) => {
const key = req.params.key
client.get(key, (error, reply) => {
if (error) res.send("Error")
else res.send(reply)
})
})
app.post("/:key", (req, res) => {
const key = req.params.key
const data = req.body
client.set(key, data, (error, reply) => {
if (error) res.send("Error")
else res.send(reply)
})
})
app.listen(port, () => {
console.log("app is listening on port " + port)
})
And you should be able to run this all with:
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