diff --git a/README.md b/README.md index 002d476..f050961 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ Key | Type | Description | Example `disableCache` | `boolean` | Optional, completely disables caching (overriden by service definitions & `fetch`'s `option` parameter) `cacheExpiration` | `number` | Optional default expiration of cached data in ms (overriden by service definitions & `fetch`'s `option` parameter) `cachePrefix` | `string` | Optional, prefix of the keys stored on your cache, defaults to `offlineApiCache` +`ignoreHeadersWhenCaching` | `boolean` | Optional, your requests will be cached independently from the headers you sent. Defaults to `false` `capServices` | `boolean` | Optional, enable capping for every service, defaults to `false`, see [limiting the size of your cache](#limiting-the-size-of-your-cache) `capLimit` | `number` | Optional quantity of cached items for each service, defaults to `50`, see [limiting the size of your cache](#limiting-the-size-of-your-cache) `offlineDriver` | `IAPIDriver` | Optional, see [use your own driver for caching](#use-your-own-driver-for-caching) @@ -180,6 +181,7 @@ Key | Type | Description | Example `disableCache` | `boolean` | Optional, disables the cache for this service (override your [API's global options](#api-options)) `capService` | `boolean` | Optional, enable or disable capping for this specific service, see [limiting the size of your cache](#limiting-the-size-of-your-cache) `capLimit` | `number` | Optional quantity of cached items for this specific service, defaults to `50`, see [limiting the size of your cache](#limiting-the-size-of-your-cache) +`ignoreHeadersWhenCaching` | `boolean` | Optional, your requests will be cached independently from the headers you sent. Defaults to `false` `rawData` | `boolean` | Disables JSON parsing from your network requests, useful if you want to fetch XML or anything else from your api ## Fetch options diff --git a/demo/package.json b/demo/package.json index f629c3e..2c04609 100644 --- a/demo/package.json +++ b/demo/package.json @@ -9,7 +9,7 @@ "dependencies": { "react": "16.0.0-alpha.12", "react-native": "0.47.1", - "react-native-offline-api": "2.0.0" + "react-native-offline-api": "2.1.0" }, "devDependencies": { "babel-jest": "20.0.3", diff --git a/dist/index.js b/dist/index.js index c1248c4..58d1a70 100644 --- a/dist/index.js +++ b/dist/index.js @@ -54,6 +54,7 @@ var DEFAULT_API_OPTIONS = { disableCache: false, cacheExpiration: 5 * 60 * 1000, cachePrefix: 'offlineApiCache', + ignoreHeadersWhenCaching: false, capServices: false, capLimit: 50 }; @@ -73,7 +74,7 @@ var OfflineFirstAPI = /** @class */ (function () { } OfflineFirstAPI.prototype.fetch = function (service, options) { return __awaiter(this, void 0, void 0, function () { - var serviceDefinition, _a, fullPath, withoutQueryParams, middlewares, fetchOptions, fetchHeaders, shouldUseCache, requestId, expiration, _sha, expirationDelay, cachedData, parsedResponseData, res, _b, err_1; + var serviceDefinition, _a, fullPath, withoutQueryParams, middlewares, fetchOptions, fetchHeaders, shouldUseCache, expiration, requestId, expirationDelay, cachedData, parsedResponseData, res, _b, err_1; return __generator(this, function (_c) { switch (_c.label) { case 0: @@ -91,11 +92,8 @@ var OfflineFirstAPI = /** @class */ (function () { fetchOptions = _merge(middlewares, (options && options.fetchOptions) || {}, { method: serviceDefinition.method }, { headers: (options && options.headers) || {} }); fetchHeaders = options && options.fetchHeaders; shouldUseCache = this._shouldUseCache(serviceDefinition, options); - requestId = void 0; expiration = void 0; - _sha = new sha('SHA-1', 'TEXT'); - _sha.update(fullPath + ":" + (fetchHeaders ? 'headersOnly' : '') + ":" + JSON.stringify(fetchOptions)); - requestId = _sha.getHash('HEX'); + requestId = this._buildRequestId(serviceDefinition, fullPath, fetchHeaders, fetchOptions, options); expirationDelay = (options && options.expiration) || serviceDefinition.expiration || this._APIOptions.cacheExpiration; expiration = Date.now() + expirationDelay; return [4 /*yield*/, this._getCachedData(service, requestId, fullPath)]; @@ -543,6 +541,22 @@ var OfflineFirstAPI = /** @class */ (function () { }); }); }; + OfflineFirstAPI.prototype._buildRequestId = function (serviceDefinition, fullPath, fetchHeaders, mergedOptions, // fully merged options + fetchOptions // fetch options + ) { + var ignoreHeadersWhenCaching = this._APIOptions.ignoreHeadersWhenCaching || + serviceDefinition.ignoreHeadersWhenCaching || + (fetchOptions && fetchOptions.ignoreHeadersWhenCaching); + var _sha = new sha('SHA-1', 'TEXT'); + var requestStringId = fullPath + ":" + (fetchHeaders ? 'headersOnly' : ''); + Object.keys(mergedOptions).forEach(function (key) { + if (!ignoreHeadersWhenCaching || key !== 'headers') { + requestStringId += JSON.stringify(mergedOptions[key]); + } + }); + _sha.update(requestStringId); + return _sha.getHash('HEX'); + }; /** * Helper returning the full URL of a service and its options. * @private diff --git a/package.json b/package.json index c5e4b96..f66e0fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-offline-api", - "version": "2.0.0", + "version": "2.1.0", "description": "Offline first API wrapper for react-native", "main": "./dist/index.js", "types": "./src/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 6dcda9e..25ff7bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ const DEFAULT_API_OPTIONS = { disableCache: false, cacheExpiration: 5 * 60 * 1000, cachePrefix: 'offlineApiCache', + ignoreHeadersWhenCaching: false, capServices: false, capLimit: 50 }; @@ -67,13 +68,8 @@ export default class OfflineFirstAPI { ); const fetchHeaders = options && options.fetchHeaders; const shouldUseCache = this._shouldUseCache(serviceDefinition, options); - let requestId; let expiration; - - // Build a short, hashed, identifier for that request - const _sha = new sha('SHA-1', 'TEXT'); - _sha.update(`${fullPath}:${fetchHeaders ? 'headersOnly' : ''}:${JSON.stringify(fetchOptions)}`); - requestId = _sha.getHash('HEX'); + const requestId = this._buildRequestId(serviceDefinition, fullPath, fetchHeaders, fetchOptions, options); // Expiration priority : option parameter of fetch() > service definition > default setting const expirationDelay = @@ -426,6 +422,31 @@ export default class OfflineFirstAPI { } } + private _buildRequestId ( + serviceDefinition: IAPIService, + fullPath: string, + fetchHeaders: boolean, + mergedOptions?: IFetchOptions, // fully merged options + fetchOptions?: IFetchOptions // fetch options + ): string { + const ignoreHeadersWhenCaching = + this._APIOptions.ignoreHeadersWhenCaching || + serviceDefinition.ignoreHeadersWhenCaching || + (fetchOptions && fetchOptions.ignoreHeadersWhenCaching); + + const _sha = new sha('SHA-1', 'TEXT'); + let requestStringId = `${fullPath}:${fetchHeaders ? 'headersOnly' : ''}`; + + Object.keys(mergedOptions).forEach((key) => { + if (!ignoreHeadersWhenCaching || key !== 'headers') { + requestStringId += JSON.stringify(mergedOptions[key]); + } + }); + + _sha.update(requestStringId); + return _sha.getHash('HEX'); + } + /** * Helper returning the full URL of a service and its options. * @private diff --git a/src/interfaces.ts b/src/interfaces.ts index 0cef1d9..a1270c9 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -7,6 +7,7 @@ export interface IAPIOptions { disableCache?: boolean; cacheExpiration?: number; cachePrefix?: string; + ignoreHeadersWhenCaching?: boolean; capServices?: boolean; capLimit?: number; offlineDriver: IAPIDriver; @@ -19,6 +20,7 @@ export interface IAPIService { domain?: string; prefix?: string; middlewares?: APIMiddleware[]; + ignoreHeadersWhenCaching?: boolean; disableCache?: boolean; capService?: boolean; capLimit?: number;