0

I'm using angular Http Interceptor to catch request and, in case that these request were already made, the interceptor just returns the HttpResponse cached on a service.

The interceptors fires with this piece of code that makes request to the API:

getSeriesWithGenres() {
    const series$ = this.getSeries()
    const genres$ = this.getGenres()

    return forkJoin([series$, genres$]).pipe(
      map(([series, genres]) => {
        return series.map((serie: Serie) => {
          serie.genre_ids = serie.genre_ids.map(genreId => {
            return genres.find((genre: Genre) => genre.id === genreId)?.name
          })

          return serie
        })
      })
    )
}

And the methods getSeries() and getGenres() made the Http Request as follows:

getSeries() {
    return this.http
      .get<ApiResponse>(
        `
        https://api.themoviedb.org/3/tv/popular?api_key=${environment.apiKey}&language=en-US
        `
      )
      .pipe(map((data: ApiResponse) => data.results as Serie[]))
  }

getGenres() {
    return this.http
      .get(
        `
        https://api.themoviedb.org/3/genre/tv/list?api_key=${environment.apiKey}&language=en-US
        `
      )
      .pipe(map((data: any) => data.genres))
}

So, my problem is when I cached the response, because if method called getSeriesWithGenres() fires twice, Iḿ getting the following error:

TypeError: "genre_ids" is read-only

Note: To cached the response I use the following data structure on another service:

private cache: Map<string, [Date | null, HttpResponse<unknown>]> = new Map()

With the corresponding getters and setters methods

And my interceptor, use this service as follows:

const HALF_HOUR = 1800
const TIME_TO_LIVE = HALF_HOUR

@Injectable()
export class CachingInterceptor implements HttpInterceptor {
  constructor(private cacheResolver: CacheResolverService) {}
  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    if (request.method !== 'GET') {
      return next.handle(request)
    }
    console.log('CachingInterceptor: ' + request.url)
    const cachedResponse = this.cacheResolver.get(request.url)
    console.log('CachedResponse:' + JSON.stringify(cachedResponse?.body))
    return cachedResponse ? of(cachedResponse) : this.sendRequest(request, next)
  }

  sendRequest(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(
      map((event: HttpEvent<unknown>) => {
        if (event instanceof HttpResponse) {
          this.cacheResolver.set(request.url, event, TIME_TO_LIVE)
        }
        return event
      })
    )
  }
}

1 Answer 1

2

The cache sets the content as frozen/read-only, to avoid you tampering with the cache.

Try updating the stream yourself :

getSeriesWithGenres() {
    const series$ = this.getSeries()
    const genres$ = this.getGenres()

    return forkJoin([series$, genres$]).pipe(
      map(([series, genres]) => series.map(serie => ({
        ...serie,
        genre_ids: serie.genre_ids.map(
          genreId => genres.find((genre: Genre) => genre.id === genreId)?.name
        )
      }))),
    )
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.