ngneat / cashew

🐿 A flexible and straightforward library that caches HTTP requests in Angular
https://www.netbasal.com
MIT License
682 stars 33 forks source link

feat: add modern provide* api-s #93

Closed eneajaho closed 9 months ago

eneajaho commented 1 year ago

I'm submitting a...


[x] Feature request

Current behavior

Currently we have to use importProvidersFrom(HttpCacheInterceptorModule.forRoot()) in order to use the lib on apps that are built with standalone bootstrap api-s.

Also, we need to use withInterceptorsFromDi() in the provideHttpClient() in order for the cache interceptor to be registered as it's a class based interceptor.

Expected behavior

Add some new api-s that export the providers using sth like:

provideHttpCache()

And inside it we can add all the providers needed for the lib to work, So basically we can just add sth like this (that we also can reuse in the module that the lib already uses, so no duplicated code):

export const provideHttpCache = (config: Partial<HttpCacheConfig> = {}) => {
  const providers: (Provider | EnvironmentProviders)[] = [
    { provide: HTTP_CACHE_CONFIG, useValue: { ...defaultConfig, ...config } },
    { provide: KeySerializer, useClass: DefaultKeySerializer },
    { provide: HttpCacheStorage, useClass: DefaultHttpCacheStorage },
    { provide: TTLManager, useClass: DefaultTTLManager },
    { provide: HttpCacheGuard, useClass: DefaultHttpCacheGuard },
    { provide: HttpCacheVersions, useClass: DefaultHttpVersions },
    HttpCacheManager,
    RequestsQueue,
    RequestsCache,

    config.skipInterceptorDeclaration 
      ? [] 
      : provideHttpClient(withInterceptors([httpCacheInterceptor])) // --> This is not recommended. 

     config.skipInterceptorDeclaration 
      ? [] 
      : { provide: HTTP_INTERCEPTOR_FNS, useValue: httpCacheInterceptor, multi: true } // --> Maybe we can do this in the future
  ];

  return makeEnvironmentProviders(providers);
};

What is the motivation / use case for changing the behavior?

Better align with the direction of Angular libs.

eneajaho commented 1 year ago

Regarding registering the interceptor, I opened an issue in the Angular repo as currently there's no way to register an interceptor directly from the library if we use functional interceptors.

https://github.com/angular/angular/issues/51303

shaharkazaz commented 1 year ago

@eneajaho You are welcome to open a PR 🙂

eneajaho commented 1 year ago

@shaharkazaz Will do, but after I get some more information about the interceptor registering part.

Maybe we can just fallback to tell the developer to register the interceptor themselves.

So, it would be sth like:

app.config.ts

providers: [
  provideHttpClient(withInterceptors([
    httpCacheInterceptor // --> This will be imported from cashew
  ])),
  provideHttpCache() // --> Register other providers. 
]
JeanMeche commented 1 year ago

This is what I would recommend, as Joost stated on the angular/angular#51303, interceptors are sensitive to ordering. They should be registered in a single place.

muuvmuuv commented 1 year ago

I think you can already use it like this:

export function provideHttp(): EnvironmentProviders[] {
  return [
    provideHttpClient(
      withInterceptors([
        logInterceptor,
        tokenInterceptor,
        metaInterceptor,
        errorInterceptor,
      ]),
      withXsrfConfiguration({
        cookieName: 'x-csrf-token',
        headerName: 'X-CSRF-Token',
      }),
      withFetch(),
    ),
    importProvidersFrom(
      HttpCacheInterceptorModule.forRoot({
        ttl: 1000 * 60 * 10,
        strategy: 'explicit',
      }),
    ),
    makeEnvironmentProviders(useHttpCacheLocalStorage),
  ]
}
JonasDev17 commented 1 year ago

I am a bit confused, I configured mine like this:

image

but looking at my localstorage I can only see a few files from assets and two requests being cached. All the other requests are just not being cached.

Am I doing something wrong?

eneajaho commented 1 year ago

I am a bit confused, I configured mine like this:

image

but looking at my localstorage I can only see a few files from assets and two requests being cached. All the other requests are just not being cached.

Am I doing something wrong?

You need withInterceptorsFromDi() inside provideHttpClient()

JonasDev17 commented 1 year ago

I am a bit confused, I configured mine like this: image but looking at my localstorage I can only see a few files from assets and two requests being cached. All the other requests are just not being cached. Am I doing something wrong?

You need withInterceptorsFromDi() inside provideHttpClient()

I tried that, but it does not make a difference. This is what I see in my localstorage:

image

But it should cache a lot more requests.

JonasDev17 commented 1 year ago

I don't know what changed but its working now.... Thanks!

waltercruz commented 1 year ago

could someone provide a clear example on how to configure cashew when using standalone bootstrap? Thanks on advance!

muuvmuuv commented 9 months ago

Seems to work with withInterceptorsFromDi but my response headers are not existing and no longer HttpHeaders and therefore .get() does not work.