I am using nestjs and would like to write a function returning Observable
(rxjs) with cache.
import { HttpService } from '@nestjs/axios';
import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { map, of, Observable } from 'rxjs';
interface User {
id: string;
// ...
}
@Injectable()
export class Service {
constructor(
@Inject(CACHE_MANAGER) protected cache: Cache,
protected readonly httpService: HttpService,
) {}
fetchUser = (id: string): Observable<User> {
const url = 'xxx';
const user: string = this.cache.get(`user:${id}`); // but here is `Promise<string>` actually
if (user) {
return of(JSON.parse(user) as User);
}
return this.httpService.get<User>(url).pipe(
map(({ data }) => {
this.cache.set(`user:${id}`, JSON.stringify(data));
return data;
})
);
}
}
The logic is quite simple, if there is cache, return cache, otherwise call api, save to cache, and return result. The only issue is that cache would return a promise. How to make this work?
CodePudding user response:
You could use RxJS from
function to convert the Promise to an Observable. From there, you could use switchMap
operator of
function to either return the user fetched from the cache or make a HTTP call.
fetchUser(id: string): Observable<User> {
const url = 'xxx';
const user$ = this.httpService.get<User>(url).pipe(
map(({ data }) => {
this.cache.set(`user:${id}`, JSON.stringify(data));
return data;
})
);
return from(this.cache.get(`user:${id}`)).pipe(
switchMap((user: string) =>
!!user ? of(user) : user$
)
);
}