Home > Blockchain >  How to use promise/async in function returning Observable?
How to use promise/async in function returning Observable?

Time:10-20

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$
    )
  );
}
  • Related