All Projects → ngneat → Cashew

ngneat / Cashew

Licence: mit
🐿 A flexible and straightforward library that caches HTTP requests in Angular

Programming Languages

typescript
32286 projects

Labels

Projects that are alternatives of or similar to Cashew

Evurlcache
a NSURLCache subclass for handling all web requests that use NSURLRequest
Stars: ✭ 287 (-19.15%)
Mutual labels:  cache
Guzzle Cache Middleware
A HTTP Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack.
Stars: ✭ 325 (-8.45%)
Mutual labels:  cache
Net
Android上强大的网络请求
Stars: ✭ 344 (-3.1%)
Mutual labels:  cache
Easystash
🗳Easy data persistence in Swift
Stars: ✭ 303 (-14.65%)
Mutual labels:  cache
Fwplayer
A video player SDK for iOS, it is based on AVPlayer. https://se.linkedin.com/in/foks-huiwang, https://fokswang.wixsite.com/home
Stars: ✭ 321 (-9.58%)
Mutual labels:  cache
Daisynet
1. - Alamofire与Cache封装 , 更容易存储请求数据. 2. - 封装Alamofire下载,使用更方便
Stars: ✭ 331 (-6.76%)
Mutual labels:  cache
Cache
Async, Promise-based cache interface for ReactPHP.
Stars: ✭ 280 (-21.13%)
Mutual labels:  cache
Django Watchman
django-watchman exposes a status endpoint for your backing services like databases, caches, etc.
Stars: ✭ 357 (+0.56%)
Mutual labels:  cache
Koa Redis
Redis storage for Koa session middleware/cache with Sentinel and Cluster support
Stars: ✭ 324 (-8.73%)
Mutual labels:  cache
Hibernate Redis
hibernate 2nd level cache privder using redis
Stars: ✭ 345 (-2.82%)
Mutual labels:  cache
Cache
Cache library
Stars: ✭ 310 (-12.68%)
Mutual labels:  cache
Apex Recipes
A library of concise, meaningful examples of Apex code for common use cases following best practices.
Stars: ✭ 307 (-13.52%)
Mutual labels:  cache
Compoxure
Proxy middleware for express that enables composition of microservices.
Stars: ✭ 332 (-6.48%)
Mutual labels:  cache
Senparc.co2net
支持 .NET Framework & .NET Core 的公共基础扩展库
Stars: ✭ 289 (-18.59%)
Mutual labels:  cache
Kache
A simple in memory cache written using go
Stars: ✭ 349 (-1.69%)
Mutual labels:  cache
Redisson
Redisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache ...
Stars: ✭ 17,972 (+4962.54%)
Mutual labels:  cache
Cache
The Cache component provides an extended PSR-6 implementation for adding cache to your applications.
Stars: ✭ 3,606 (+915.77%)
Mutual labels:  cache
Cachier
Persistent, stale-free, local and cross-machine caching for Python functions.
Stars: ✭ 359 (+1.13%)
Mutual labels:  cache
Ssm booksystem
ssm demo,ssm详细教程,SSM简明教程:简单的十步教你搭建人生第一个SSM框架[ SSM框架整合教程(spring+spring mvc+mybatis+redis+maven+idea+bootstrap) ]
Stars: ✭ 355 (+0%)
Mutual labels:  cache
Cache
Cache library with Redis backend for Golang
Stars: ✭ 337 (-5.07%)
Mutual labels:  cache

Caching is nut a problem!


Build Status MIT coc-badge commitizen PRs styled with prettier All Contributors ngneat

Features

✅ HTTP Caching
✅ Local Storage Support
✅ Handles Simultaneous Requests
✅ Automatic & Manual Cache Busting
✅ Hackable

A flexible and straightforward library that caches HTTP requests in Angular

Buy Me A Coffee

Installation

NPM

$ npm install @ngneat/cashew

Usage

Inject the HttpCacheInterceptorModule module along with HttpClientModule into you root module:

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpCacheInterceptorModule } from '@ngneat/cashew';

@NgModule({
  imports: [HttpClientModule, HttpCacheInterceptorModule.forRoot()],
  bootstrap: [AppComponent]
})
export class AppModule {}

And you're done! Now, when using Angular HttpClient, you can call the withCache function, and it'll cache the response:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { withCache } from '@ngneat/cashew';

@Injectable()
export class UsersService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get('api/users', withCache());
  }
}

It's as simple as that.

Local Storage

By default caching is done to app memory. To switch to using local storage instead simply add:

import { HttpCacheInterceptorModule, useHttpCacheLocalStorage } from '@ngneat/cashew';

@NgModule({
  imports: [HttpClientModule, HttpCacheInterceptorModule.forRoot()],
  providers: [useHttpCacheLocalStorage],
  bootstrap: [AppComponent]
})
export class AppModule {}

To your AppModule providers list. Note that ttl will also be calculated via local storage in this instance.

Config Options

Using the library, you might need to change the default behavior of the caching mechanism. You could do that by passing a configuration (a partial HttpCacheConfig object) to the static forRoot method of the HttpCacheInterceptorModule module.

Important note: View Engine users - instead of adding the config to the forRoot() method, add it in the app module providers in the following manner, using the supplied cashewConfig() method:

{ provide: HTTP_CACHE_CONFIG, useValue: cashewConfig(config) }

Let's go over each of the configuration options:

strategy

Defines the caching behavior. The library supports two different strategies:

  • explicit (default) - only caches API requests that explicitly use the withCache function
  • implicit - caches API requests that are of type GET and the response type is JSON. You can change this behavior by overriding the HttpCacheGuard provider. (See the Hackable section)
HttpCacheInterceptorModule.forRoot({
  strategy: 'explicit'
});

localStorageKey

When using local storage for caching, this defines the key where the cache is stored (for ttl - with the "Ttl" suffix): (defaults to 'httpCache')

HttpCacheInterceptorModule.forRoot({
  localStorageKey: string
});

ttl

Define the cache TTL (time to live) in milliseconds: (defaults to one hour)

HttpCacheInterceptorModule.forRoot({
  ttl: number
});

responseSerializer

By default, the registry returns the original response object. It can be dangerous if, for some reason, you mutate it. To change this behavior, you can clone the response before getting it:

HttpCacheInterceptorModule.forRoot({
  responseSerializer(body) {
    return cloneDeep(body);
  }
});

parameterCodec

Define the HttpParameterCodec implementation if you need a different parameter encoder.

Example of custom implementation that uses encodeURIComponent:

import { HttpCacheInterceptorModule, useHttpCacheLocalStorage } from '@ngneat/cashew';
import { HttpParameterCodec } from '@angular/common/http';

class CustomHttpParameterCodec implements HttpParameterCodec {
  encodeKey(key: string): string {
    return encodeURIComponent(key);
  }
  encodeValue(value: string): string {
    return encodeURIComponent(value);
  }
  decodeKey(key: string): string {
    return decodeURIComponent(key);
  }
  decodeValue(value: string): string {
    return decodeURIComponent(value);
  }
}

@NgModule({
  imports: [
    HttpClientModule,
    HttpCacheInterceptorModule.forRoot({ parameterCodec: new CustomHttpParameterCodec() })
  ],
  providers: [useHttpCacheLocalStorage],
  bootstrap: [AppComponent]
})
export class AppModule {}

or per request:

class CustomHttpParameterCodec implements HttpParameterCodec {
  ...
}

@Injectable()
export class UsersService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get(
      'api/users',
      withCache({
        parameterCodec$: new CustomHttpParameterCodec(),
        ...
      })
    );
  }
}

API

WithCache

Currently, there is no way in Angular to pass metadata to an interceptor. The withCache function uses the params object to pass the config and removes it afterward in the interceptor. The function receives four optional params that are postfixed with a $ sign so it'll not conflicts with others:

  • cache$ - Whether to cache the request (defaults to true)
  • ttl$ - TTL that will override the global
  • key$ - Custom key. (defaults to the request URL including any query params)
  • bucket$ - The bucket in which we save the keys
@Injectable()
export class UsersService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get(
      'api/users',
      withCache({
        withCache$: false,
        ttl$: 40000,
        key$: 'yourkey'
      })
    );
  }
}

In addition to that, you can pass any query parameter that you need:

@Injectable()
export class UsersService {
  constructor(private http: HttpClient) {}

  getUser(id) {
    return this.http.get(
      'api/users',
      withCache({
        id,
        ttl$: 40000
      })
    );
  }
}

CacheManager

The CacheManager provider, exposes an API to update and query the cache registry:

  • get<T>(key: string): HttpResponse<T> - Get the HttpResponse from the cache
  • has(key: string) - Returns a boolean indicates whether the provided key exists in the cache
  • set(key: string, body: any, { ttl, bucket }) - Set manually a new entry in the cache
  • delete(key: string | RegExp | CacheBucket) - Delete from the cache

CacheBucket

CacheBucket can be useful when we need to buffer multiple requests and invalidate them at some point. For example:

import { withCache, CacheBucket } from '@ngneat/cashew';

@Injectable()
export class TodosService {
  todosBucket = new CacheBucket();

  constructor(private http: HttpClient, private manager: HttpCacheManager) {}

  getTodo(id) {
    return this.http.get(
      `todos/${id}`,
      withCache({
        bucket$: this.todosBucket
      })
    );
  }

  invalidateTodos() {
    this.manager.delete(this.todosBucket);
  }
}

Now when we call the invalidateTodos method, it'll automatically delete all the ids that it buffered. CacheBucket also exposes the add, has, delete, and clear methods.

Hack the Library

  • HttpCacheStorage - The storage to use: (defaults to in-memory storage)
class HttpCacheStorage {
  abstract has(key: string): boolean;
  abstract get(key: string): HttpResponse<any>;
  abstract set(key: string, response: HttpResponse<any>): void;
  abstract delete(key?: string | RegExp): void;
}
  • KeySerializer - Generate the cache key based on the request: (defaults to request.urlWithParams)
export abstract class KeySerializer {
  abstract serialize(request: HttpCacheRequest): string;
}
  • HttpCacheGuard - When using the implicit strategy it first verifies that canActivate is truthy:
export abstract class HttpCacheGuard {
  abstract canActivate(request: HttpCacheRequest): boolean;
}

It defaults to request.method === 'GET' && request.responseType === 'json'.

  • TTLManager - A class responsible for managing the requests TTL:
abstract class TTLManager {
  abstract isValid(key: string): boolean;
  abstract set(key: string, ttl?: number): void;
  abstract delete(key?: string | RegExp): void;
}

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Netanel Basal

💻 🎨 📖 🤔 🚇

Itay Oded

💻

Shahar Kazaz

💻

Lars Gyrup Brink Nielsen

📖

Raí Siqueira

🖋

Inbal Sinai

💻 📖

James Manners

💻

mokipedia

💻 📖

This project follows the all-contributors specification. Contributions of any kind welcome!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].