npm package: @fastify/redis
Description: Plugin to share a common Redis connection across Fastify.
Author: Tomas Della Vedova - @delvedor
Latest version: 7.2.0

# @fastify/redis

[![CI](https://github.com/fastify/fastify-redis/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-redis/actions/workflows/ci.yml)
[![NPM version](https://img.shields.io/npm/v/@fastify/redis.svg?style=flat)](https://www.npmjs.com/package/@fastify/redis)
[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)

Fastify Redis connection plugin; with this you can share the same Redis connection in every part of your server.

## Install

```
npm i @fastify/redis
```

### Compatibility
| Plugin version | Fastify version |
| ---------------|-----------------|
| `>=7.x`        | `^5.x`          |
| `^6.x`         | `^4.x`          |
| `>=4.x <6.x`   | `^3.x`          |
| `^3.x`         | `^2.x`          |
| `>=1.x <3.x`   | `^1.x`          |


Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin
in the table above.
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.

## Usage

Add it to your project with `register` and you are done!

### Create a new Redis Client

Under the hood [ioredis](https://github.com/luin/ioredis) is used as client, the ``options`` that you pass to `register` will be passed to the Redis client.

```js
const fastify = require('fastify')()

// create by specifying host
fastify.register(require('@fastify/redis'), { host: '127.0.0.1' })

// OR by specifying Redis URL
fastify.register(require('@fastify/redis'), { url: 'redis://127.0.0.1', /* other redis options */ })

// OR with more options
fastify.register(require('@fastify/redis'), {
  host: '127.0.0.1',
  password: '***',
  port: 6379, // Redis port
  family: 4   // 4 (IPv4) or 6 (IPv6)
})
```

### Accessing the Redis Client

Once you have registered your plugin, you can access the Redis client via `fastify.redis`.

The client is automatically closed when the fastify instance is closed.

```js
'use strict'

const Fastify = require('fastify')
const fastifyRedis = require('@fastify/redis')

const fastify = Fastify({ logger: true })

fastify.register(fastifyRedis, {
  host: '127.0.0.1',
  password: 'your strong password here',
  port: 6379, // Redis port
  family: 4   // 4 (IPv4) or 6 (IPv6)
})

fastify.get('/foo', (req, reply) => {
  const { redis } = fastify
  redis.get(req.query.key, (err, val) => {
    reply.send(err || val)
  })
})

fastify.post('/foo', (req, reply) => {
  const { redis } = fastify
  redis.set(req.body.key, req.body.value, (err) => {
    reply.send(err || { status: 'ok' })
  })
})

fastify.listen({ port: 3000 }, err => {
  if (err) throw err
  console.log(`server listening on ${fastify.server.address().port}`)
})
```

### Using an existing Redis client

You may also supply an existing *Redis* client instance by passing an options
object with the `client` property set to the instance. In this case,
the client is not automatically closed when the Fastify instance is
closed.

```js
'use strict'

const fastify = require('fastify')()
const Redis = require('ioredis')

const client = new Redis({ host: 'localhost', port: 6379 })

fastify.register(require('@fastify/redis'), { client })
```

You can also supply a *Redis Cluster* instance to the client:

```js
'use strict'

const fastify = require('fastify')()
const Redis = require('ioredis')

const client = new Redis.Cluster([{ host: 'localhost', port: 6379 }]);

fastify.register(require('@fastify/redis'), { client })
```

Note: by default, *@fastify/redis* will **not** automatically close the client
connection when the Fastify server shuts down.

To automatically close the client connection, set clientClose to true.

```js
fastify.register(require('@fastify/redis'), { client, closeClient: true })
```

## Registering multiple Redis client instances

By using the `namespace` option you can register multiple Redis client instances.

```js
'use strict'

const fastify = require('fastify')()

fastify
  .register(require('@fastify/redis'), {
    host: '127.0.0.1',
    port: 6380,
    namespace: 'hello'
  })
  .register(require('@fastify/redis'), {
    client: redis,
    namespace: 'world'
  })

// Here we will use the `hello` named instance
fastify.get('/hello', (req, reply) => {
  const { redis } = fastify

  redis.hello.get(req.query.key, (err, val) => {
    reply.send(err || val)
  })
})

fastify.post('/hello', (req, reply) => {
  const { redis } = fastify

  redis['hello'].set(req.body.key, req.body.value, (err) => {
    reply.send(err || { status: 'ok' })
  })
})

// Here we will use the `world` named instance
fastify.get('/world', (req, reply) => {
  const { redis } = fastify

  redis['world'].get(req.query.key, (err, val) => {
    reply.send(err || val)
  })
})

fastify.post('/world', (req, reply) => {
  const { redis } = fastify

  redis.world.set(req.body.key, req.body.value, (err) => {
    reply.send(err || { status: 'ok' })
  })
})

fastify.listen({ port: 3000 }, function (err) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

```

## Redis streams (Redis 5.0 or greater is required)

`@fastify/redis` supports Redis streams out of the box.

```js
'use strict'

const fastify = require('fastify')()

fastify.register(require('@fastify/redis'), {
  host: '127.0.0.1',
  port: 6380
})

fastify.get('/streams', async (request, reply) => {
  // We write an event to the stream 'my awesome fastify stream name', setting 'key' to 'value'
  await fastify.redis.xadd(['my awesome fastify stream name', '*', 'hello', 'fastify is awesome'])

  // We read events from the beginning of the stream called 'my awesome fastify stream name'
  let redisStream = await fastify.redis.xread(['STREAMS', 'my awesome fastify stream name', 0])

  // We parse the results
  let response = []
  let events = redisStream[0][1]

  for (let i = 0; i < events.length; i++) {
    const e = events[i]
    response.push(`#LOG: id is ${e[0].toString()}`)

    // We log each key
    for (const key in e[1]) {
      response.push(e[1][key].toString())
    }
  }

  reply.status(200)
  return { output: response }
  // Will return something like this :
  // { "output": ["#LOG: id is 1559985742035-0", "hello", "fastify is awesome"] }
})

fastify.listen({ port: 3000 }, function (err) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})
```
> ℹ️ Note: you can find more information about Redis streams and the relevant commands [here](https://redis.io/topics/streams-intro) and [here](https://redis.io/commands#stream).

## Redis connection error
The majority of errors are silent due to the `ioredis` silent error handling but during the plugin registration it will check that the connection with the redis instance is correctly estabilished.
In this case, you can receive an `ERR_AVVIO_PLUGIN_TIMEOUT` error if the connection cannot be established in the expected time frame or a dedicated error for an invalid connection.

## Acknowledgments

This project is kindly sponsored by:
- [nearForm](https://nearform.com)
- [LetzDoIt](https://www.letzdoitapp.com/)

## License

Licensed under [MIT](./LICENSE).