NestJS with node-redis - redis

Wondering if anyone could help me out with this, as I'm new to NestJS.
I'm trying to use Redis in my existing NestJS service, rather than creating a separate microservice like Nest documents in their examples. When I import redis from node-redis it comes back as undefined.
token.service.ts
import { Injectable } from '#nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import redis from 'redis';
#Injectable()
export class TokenService {
constructor() {
// create new redis client with default options
this.client = redis.createClient();
this.client.on('error', err => console.error(err));
}
...
}
The error I'm getting: Cannot read property 'createClient' of undefined
I've never seen undefined imports in Node, so I'm wondering if this a NestJS specific issue, or if it has to do with the redis package I'm using.
Any help is appreciated.

You're likely having an issue with the import statement.
Try replacing
import redis from 'redis';
with:
import * as redis from 'redis';
or
const redis = require('redis');

Related

What's the right way to publish Redis message from a Redis based NestJS Microservice

I built a sample Redis based Microservice with NestJS. It's fantastic and works great. In my microservice, after processing the message received over Redis (pub/sub), we publish our result to another Redis channel for a different microservice to pick.
What's the right way to publish? Are there any samples?
For my work, I used Redis package and published it (as opposed to ClientProxyFactory). Works fine and gets the job done.
import {
ClientProxy,
ClientProxyFactory,
Transport,
} from '#nestjs/microservices';
import { Injectable, Logger } from '#nestjs/common';
import * as redis from 'redis';
import { NVResponseDTO } from "../dto/nv.dto";
#Injectable()
export class NVPersistService {
logger = new Logger('NVPersistService');
private client: redis.RedisClient;
constructor() {
this.client = redis.createClient({port: 6379, host: 'localhost'});
this.logger.log('Successfully created client for publish');
}
async publish(result: NVResponseDTO) {
const channel = 'persistence';
try {
await this.client.publish(channel, JSON.stringify(result));
this.logger.log(`Message sent`);
} catch (e) {
this.logger.error(e);
}
}
}
But is this the way to do it or should I use something like below
this.client = ClientProxyFactory.create({
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
}
});
await this.client.connect();
const channel = 'persistence';
const status = await this.client.send<string, NVResponseDTO>(channel, result);
this.logger.log(`Status of send - ${status}`);
Note: Above code did not work for me, hence used Redis directly. Any guidance would be much appreciated

Store a value in redis store using Nestjs

I have a simple nestjs application, where I have set up a CacheModule using Redis store as follows:
import * as redisStore from 'cache-manager-redis-store';
CacheModule.register({
store: redisStore,
host: 'redis',
port: 6379,
}),
I would like to use it to store a single value, however, I do not want to do it the built-in way by attaching an interceptor to a controller method, but instead I want to control it manually and be able to set and retrieve the value in the code.
How would I go about doing that and would I even use cache manager for that?
You can use the official way from Nest.js:
1. Create your RedisCacheModule:
1.1. redisCache.module.ts:
import { Module, CacheModule } from '#nestjs/common';
import { ConfigModule, ConfigService } from '#nestjs/config';
import * as redisStore from 'cache-manager-redis-store';
import { RedisCacheService } from './redisCache.service';
#Module({
imports: [
CacheModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
store: redisStore,
host: configService.get('REDIS_HOST'),
port: configService.get('REDIS_PORT'),
ttl: configService.get('CACHE_TTL'),
}),
}),
],
providers: [RedisCacheService],
exports: [RedisCacheService] // This is IMPORTANT, you need to export RedisCacheService here so that other modules can use it
})
export class RedisCacheModule {}
1.2. redisCache.service.ts:
import { Injectable, Inject, CACHE_MANAGER } from '#nestjs/common';
import { Cache } from 'cache-manager';
#Injectable()
export class RedisCacheService {
constructor(
#Inject(CACHE_MANAGER) private readonly cache: Cache,
) {}
async get(key) {
await this.cache.get(key);
}
async set(key, value) {
await this.cache.set(key, value);
}
}
2. Inject RedisCacheModule wherever you need it:
Let's just assume we will use it in module DailyReportModule:
2.1. dailyReport.module.ts:
import { Module } from '#nestjs/common';
import { RedisCacheModule } from '../cache/redisCache.module';
import { DailyReportService } from './dailyReport.service';
#Module({
imports: [RedisCacheModule],
providers: [DailyReportService],
})
export class DailyReportModule {}
2.2. dailyReport.service.ts
We will use the redisCacheService here:
import { Injectable, Logger } from '#nestjs/common';
import { Cron } from '#nestjs/schedule';
import { RedisCacheService } from '../cache/redisCache.service';
#Injectable()
export class DailyReportService {
private readonly logger = new Logger(DailyReportService.name);
constructor(
private readonly redisCacheService: RedisCacheService, // REMEMBER TO INJECT THIS
) {}
#Cron('0 1 0 * * *') // Run cron job at 00:01:00 everyday
async handleCacheDailyReport() {
this.logger.debug('Handle cache to Redis');
}
}
You can check my sample code here.
Building on Ahmad's comment above, I used the following to enable redis in my nestjs application:
Install and setup nestjs-redis https://www.npmjs.com/package/nestjs-redis per docs.
See the docs here on how to write and read values in a Redis store:
https://github.com/NodeRedis/node-redis
If you're connection a external Redis, I recommend to use 'async-redis' package.
The code will be:
import * as redis from 'async-redis';
import redisConfig from '../../config/redis';
On redisConfig:
export default {
host: 'your Host',
port: parseInt('Your Port Conection'),
// Put the first value in hours
// Time to expire a data on redis
expire: 1 * 60 * 60,
auth_pass: 'password',
};
So, you run:
var dbConnection = redis.createClient(config.db.port, config.db.host,
{no_ready_check: true});
Now you can, execute commands like set and get for your Redis Database.

How can I give an option to user to set baseurl?

I have built an app using ionic but my clients will be using different servers for accessing API. How can I give an option to set the base url by the user to call the desired server API?
There are 2 ways:
The temporary way:
This way, when the app is closed, it reset to the default api:
create a service ionic generate service
in this service, make a variable that will have the url you need
make some getter and setter
import this service where you need it (were you change your api, and in your api service)
The permanent way:
Use the file plugin to make, for example, a JSON that you will read/write with the api url in it.
set your base url in environment.ts file and use in any of service
export const environment = {
production: false,
baseUrl: 'http://localhost:3000/'
};
auth.service.ts
import { Injectable } from '#angular/core';
import { Observable} from 'rxjs';
import { HttpClient } from '#angular/common/http';
import { environment } from '../../../environments/environment';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.baseUrl;
constructor(
private http: HttpClient
) { }
Userlogin(data: any): Observable<any> {
return this.http.post(this.baseUrl + 'user/login', data);
}
}

How to use combineLatest and takeUntil rxjs operators in Angular 5

I see that in Angular 5 one should be using rxjs operators differently and importing from 'rxjs/operators' but I'm a little unclear on how it is supposed to work. I have something like:
import { Observable } from 'rxjs/Observable';
import { combineLatest, takeUntil } from 'rxjs/operators';
#Component({ ... })
export class FooComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route_data = Observable.combineLatest(this.route.params, this.route.data,
(params, data) => ({params,data}));
this.route_data_sub = this.route_data.takeUntil(this.destroyed$).subscribe(
(params_and_data) => {
...
}
}
...
}
but I'm getting Observable.combineLatest is not a function errors. If I add the combineLatest operator the old way it works for combineLatest, but then takeUntil is now not found. How is this supposed to be done with Angular 5?
I have quite a bit of rxjs code all over the app and don't know how it is supposed to be rewritten or how to change the imports. Does everything have to be rewritten with .pipe() now?
You should import combileLatest use
import { combineLatest } from 'rxjs/observable/combineLatest';
For takeUntil
import { takeUntil } 'rxjs/operators';
I found that information:
combineLatest
takeUntil
#Mad Dandelion has the right answer but I figured it's worth showing what it looks like putting it together for anyone running across the same thing. You do have to pipe things like takeUntil. It's a bit of a pain to go through a large app and find all these spots but doesn't take that long. Doesn't look that bad either and has all the benefits in https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md under "why".
import { Observable } from 'rxjs/Observable';
import { combineLatest } from 'rxjs/observable/combineLatest';
import { takeUntil } from 'rxjs/operators';
#Component({ ... })
export class FooComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route_data = combineLatest(this.route.params,
this.route.data,
(params, data) => ({params,data})
);
this.route_data_sub = this.route_data
.pipe(takeUntil(this.destroyed$)) //<-- pipe()
.subscribe((params_and_data) => {
...
})
}
...
}
Also in my case I had some stale dlls serving the older rxjs (https://webpack.js.org/plugins/dll-plugin/) so if you run into something that looks like your Observables don't have the pipe property, you might want to make sure the dlls are building properly if you use that.

defining providers for an angular2 component using dart

I'm writing an angular2 dart application using Intellij.
I created a provider called Auth that should be injected to the app component.
I defined the Auth service using the following code:
import 'package:angular2/core.dart';
import 'package:auth0_lock/auth0_lock.dart';
import './config.dart';
#Injectable()
class Auth {
Auth0Lock lock;
Auth() {
this.lock = new Auth0Lock(configObj.auth0.apiKey, configObj.auth0.domain);
}
updateProfileName(data) {
var profile = data['profile'] != null ? data['profile'] : data;
print(profile['name']);
}
login() {
this.lock.show(popupMode: true, options: {'authParams': {'scope': 'openid profile'}}).then(this.updateProfileName);
}
}
and the app component using the following code:
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
import 'welcome_component.dart';
import 'auth_service.dart';
#Component(
selector: 'my-app',
templateUrl: '/www/my-app.html',
providers: [Auth]
)
#RouteConfig(const [
const Route(path: '/welcome', component: WelcomeComponent, name: 'welcome')
])
class AppComponent {
Auth auth;
AppComponent(Auth auth) {
this.auth=auth;
}
}
now intellij is complaning about the providers array with the error message arguments of constant creation must be constant expressions.
I'm new to dart... but if the Component configuration needs consts, how can I provide classes to be used there ?
thanks
Just adding const should do:
providers: const [Auth]
The error you're seeing is because [Auth] creates a List that — although it contains only a const memeber — is itself not constant. (For example, it could be added to, or cleared.) Dart requires you to specify explicitly that the List is constant.