angularangular-resolver

How to prevent a resolver from calling the same multiple http get requests


My app has several routing re-directions that each on of them triggering the FooResolverService, and each resolve invocation calls a FooService's method of GetFoos http get method (so my resource api is being requested multiple times with the same request).

How to allow only for the first invocation of the resolve to actually call the resource api via the FooService?

export class FooResolverService implements Resolve<FooModel[]> {
  constructor(    
    private fooService: FooService
  ) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    console.log("resolve");
    return this.fooService.getFoos();
  }
}

FooService:

getFoos() : FooModel[] {        
    if (this.foos.length === 0) {
        this._foosAPIService.fetchFoos().subscribe(foos => 
        {
            this.setFoos(foos);
        });
    } 
    else {
        return this.foos;
    }
}

setFoos(foos: FooModel[]) {
    this.foos = foos;
}

FoosAPIService

fetchFoos() : Observable<FooModel[]> {
    return this._httpClient
        .get<FooModel[]>(
            this._configService.resourceApiURI + 'foos/'      
        );
}

Routes

const routes: Routes = [  
  { path: '', component: FoosComponent, children: children},
  { path: ':id', component: FoosComponent, children: children, resolve: [FoosResolverService]}
];

Solution

  • As the comments suggested, I've ended up caching the Observable itself (instead of caching the results), with the help of shareReplay():

    FoosAPIService:

    fetchFoos(filter: string) : Observable<EventFoo[]> {
        if (this.fetchFoos$[filter]) {
          return this.fetchFoos$[filter];
        }
    
        this.fetchFoos$[filter] = this._httpClient
          .get<FooModel[]>(
            this._configService.resourceApiURI + 'events/'
          )
          .pipe(
            shareReplay({ bufferSize: 1, refCount: true })
          );
        
        return this.fetchFoos$[filter];
    }
    

    Service:

    fetchFoos(filter: string) : void {        
        this.foosSubscription = this._foosAPIService.fetchFoos(filter)
            .subscribe(foos => 
            {                
                this.setFoos(foos);
                this.foosSubscription.unsubscribe();
            });
    }