# IORedis
# Features
Currently, @tsed/ioredis
allows you to:
- Configure one or more Redis database connections via the
@Configuration
configuration. - Share Redis connection with
@tsed/platform-cache
. - Support classic Redis connection and Cluster connection.
- Inject connection to another service.
- Mock connection for unit/integration test.
# Installation
npm install --save @tsed/ioredis ioredis
npm install --save-dev ioredis-mock
1
2
2
Note
Minimal supported ioredis version is v5+
# Create connection
Create a new RedisConnection.ts
file in your project:
import Redis from "ioredis";
import {registerConnectionProvider} from "@tsed/ioredis";
export const REDIS_CONNECTION = Symbol.for("REDIS_CONNECTION");
export type REDIS_CONNECTION = Redis;
registerConnectionProvider({
provide: REDIS_CONNECTION,
name: "default"
});
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Note
registerConnectionProvider
creates automatically an injectable RedisConnection
.
Then, edit your Server.ts
:
import {Configuration} from "@tsed/di";
import "@tsed/platform-cache"; // add this module if you want to use cache
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
// share the Redis connection with @tsed/platform-cache
cache: true
// redis options
// host: "localhost",
// port: 6379,
// username: "...",
// password: "...",
// tls: false,
// db: 0
}
],
// cache options
cache: {
ttl: 300
}
})
class MyModule {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
And finally, use the connection in your services:
import {Injectable} from "@tsed/di";
@Injectable()
export class ClientRepository {
@Inject(REDIS_CONNECTION)
protected connection: REDIS_CONNECTION; // ioredis instance
async keys() {
return this.connection.keys("clients:*");
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
See ioredis documentation (opens new window) for more details.
# Cluster configuration
import {Configuration} from "@tsed/di";
import "@tsed/platform-cache"; // add this module if you want to use cache
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
// share the Redis connection with @tsed/platform-cache
cache: true,
// cluster options
nodes: ["..."],
// other cluster options
scaleReads: "all",
maxRedirections: 16,
retryDelayOnTryAgain: 100,
retryDelayOnFailover: 200,
retryDelayOnClusterDown: 1000,
slotsRefreshTimeout: 15000,
slotsRefreshInterval: 20000,
enableOfflineQueue: true,
enableReadyCheck: true,
redisOptions: {
noDelay: true,
connectTimeout: 15000,
autoResendUnfulfilledCommands: true,
maxRetriesPerRequest: 5,
enableAutoPipelining: true,
autoPipeliningIgnoredCommands: ["scan"]
}
//
}
],
// cache options
cache: {
ttl: 300
}
})
class MyModule {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Sentinel configuration
import {Configuration} from "@tsed/di";
import "@tsed/platform-cache"; // add this module if you want to use cache
import "@tsed/ioredis";
@Configuration({
ioredis: [
{
name: "default",
// share the redis connection with @tsed/platform-cache
cache: true,
// sentinel master name
sentinelName: "redis-master",
// sentinels nodes
sentinels: ["..."],
redisOptions: {
noDelay: true,
connectTimeout: 15000,
autoResendUnfulfilledCommands: true,
maxRetriesPerRequest: 5,
enableAutoPipelining: true,
autoPipeliningIgnoredCommands: ["scan"]
}
//
}
],
// cache options
cache: {
ttl: 300
}
})
class MyModule {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Testing
Ts.ED provides a utility that allows you to test a service that consumes a Redis connection. This use relies on the awesome ioredis-mock (opens new window) module.
Here is a class that consumes a Redis connection:
import {v4} from "uuid";
import {Injectable} from "@tsed/di";
import {serialize, deserialize} from "@tsed/json-mapper";
import {REDIS_CONNECTION} from "./RedisConnection";
import {ClientModel} from "./ClientModel";
@Injectable()
export class ClientRepository {
@Inject(REDIS_CONNECTION)
protected connection: REDIS_CONNECTION; // ioredis instance
async get(id: string) {
const raw = await this.connection.get("clients:" + id);
if (!raw) {
return undefined;
}
return deserialize(JSON.parse(raw), {type: ClientModel});
}
async save(client: ClientModel) {
client.id = client.id || v4();
this.connection.set("clients:" + client.id, JSON.stringify(serialize(client)));
return client;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
The ClientModel:
import {Schema} from "@tsed/schema";
export class ClientModel {
@Property()
id: string;
@Property()
name: string;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
And its test:
import {ClientRepository} from "./ClientRepository";
import {REDIS_CONNECTION} from "./RedisConnection";
import {ClientModel} from "./ClientModel";
describe("IORedisTest", () => {
beforeEach(() => IORedisTest.create()); // create a new sandbox with ioredis-mock connection
afterEach(() => IORedisTest.reset());
it("should return nothing", async () => {
const service = IORedisTest.get<MyRepository>(MyRepository);
const client = await service.get("uid");
expect(client).toEqual(undefined);
});
it("should return all keys", async () => {
const service = IORedisTest.get<MyRepository>(MyRepository);
const client = new ClientModel();
client.name = "name";
const newClient = await service.save(client);
expect(newClient.id).toBeInstanceOf(String);
expect(newClient.name).toEqual("name");
const clientFound = await service.get(newClient.id);
expect(clientFound).toBeInstanceOf(ClientModel);
expect(clientFound.id).toEqual(newClient.id);
expect(clientFound.name).toEqual("name");
});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Author
# Maintainers
Other topics
- Session & cookies
- Passport.js
- Keycloak
- Prisma
- TypeORM
- MikroORM
- Mongoose
- GraphQL
- GraphQL WS
- Apollo
- TypeGraphQL
- GraphQL Nexus
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Serverless HTTP
- Seq
- OIDC
- Stripe
- Agenda
- Terminus
- Serverless
- Server-sent events
- IORedis
- Vike
- Jest
- Vitest
- Controllers
- Providers
- Model
- JsonMapper
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Exceptions
- Throw HTTP Exceptions
- Cache
- Command
- Response Filter
- Injection scopes
- Custom providers
- Lazy-loading provider
- Custom endpoint decorator
- Testing
- Customize 404