fetch-dedupe
Advanced tools
Comparing version 1.0.0 to 2.0.0
# Changelog | ||
### v2.0.0 (2018/2/4) | ||
**Breaking** | ||
* `dedupeOptions` is now optional. The `responseType` is `"json"` by default, unless the | ||
status code is 204, in which case it will be `"text"`. | ||
### v1.0.0 (2018/2/4) | ||
@@ -7,4 +14,4 @@ | ||
- `init` is now optional | ||
- A `requestKey` will be generated for you if it is omitted | ||
* `init` is now optional | ||
* A `requestKey` will be generated for you if it is omitted | ||
@@ -11,0 +18,0 @@ ### v0.1.0 (2018/2/4) |
@@ -68,3 +68,4 @@ (function (global, factory) { | ||
} else { | ||
throw new Error('dedupeOptions are required.'); | ||
opts = {}; | ||
initToUse = {}; | ||
} | ||
@@ -87,4 +88,3 @@ | ||
method: initToUse.method || input.method || '', | ||
body: initToUse.body || input.body || '', | ||
responseType: responseType | ||
body: initToUse.body || input.body || '' | ||
}); | ||
@@ -114,6 +114,14 @@ | ||
var request = fetch(input, initToUse).then(function (res) { | ||
var responseTypeToUse = void 0; | ||
if (responseType) { | ||
responseTypeToUse = responseType; | ||
} else if (res.status === 204) { | ||
responseTypeToUse = 'text'; | ||
} else { | ||
responseTypeToUse = 'json'; | ||
} | ||
// The response body is a ReadableStream. ReadableStreams can only be read a single | ||
// time, so we must handle that in a central location, here, before resolving | ||
// the fetch. | ||
return res[responseType]().then(function (data) { | ||
return res[responseTypeToUse]().then(function (data) { | ||
res.data = data; | ||
@@ -120,0 +128,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(e.FetchDedupe={})}(this,function(e){"use strict";var r={};function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},r=e.url,t=e.method,o=e.responseType,n=void 0===o?"":o,i=e.body,u=void 0===i?"":i;return[void 0===r?"":r,(void 0===t?"":t).toUpperCase(),n,u].join("||")}function o(e){var t=e.requestKey,o=e.res,n=e.err;(r[t]||[]).forEach(function(e){o?e.resolve(o):e.reject(n)}),r[t]=null}e.getRequestKey=t,e.isRequestInFlight=function(e){return!!r[e]},e.clearRequestCache=function(){r={}},e.fetchDedupe=function(e,n,i){var u=void 0,d=void 0;if(i)u=i,d=n;else{if(!n||!n.responseType)throw Error("dedupeOptions are required.");u=n,d={}}var s=u.responseType,f=void 0===s?"":s,c=u.dedupe,p=void 0===c||c,v=u.requestKey||t({url:e.url||e,method:d.method||e.method||"",body:d.body||e.body||"",responseType:f}),h=void 0;if(p){r[v]||(r[v]=[]);var y=r[v],a=!!y.length,l={};if(h=new Promise(function(e,r){l.resolve=e,l.reject=r}),y.push(l),a)return h}var m=fetch(e,d).then(function(e){return e[f]().then(function(r){if(e.data=r,!p)return e;o({requestKey:v,res:e})})},function(e){if(!p)return Promise.reject(e);o({requestKey:v,err:e})});return p?h:m},Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.FetchDedupe={})}(this,function(e){"use strict";var t={};function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=e.method,o=e.responseType,n=void 0===o?"":o,u=e.body,i=void 0===u?"":u;return[void 0===t?"":t,(void 0===r?"":r).toUpperCase(),n,i].join("||")}function o(e){var r=e.requestKey,o=e.res,n=e.err;(t[r]||[]).forEach(function(e){o?e.resolve(o):e.reject(n)}),t[r]=null}e.getRequestKey=r,e.isRequestInFlight=function(e){return!!t[e]},e.clearRequestCache=function(){t={}},e.fetchDedupe=function(e,n,u){var i=void 0,d=void 0;u?(i=u,d=n):n&&n.responseType?(i=n,d={}):(i={},d={});var s=i.responseType,f=void 0===s?"":s,c=i.dedupe,v=void 0===c||c,p=i.requestKey||r({url:e.url||e,method:d.method||e.method||"",body:d.body||e.body||""}),a=void 0;if(v){t[p]||(t[p]=[]);var h=t[p],y=!!h.length,l={};if(a=new Promise(function(e,t){l.resolve=e,l.reject=t}),h.push(l),y)return a}var m=fetch(e,d).then(function(e){return e[f||(204===e.status?"text":"json")]().then(function(t){if(e.data=t,!v)return e;o({requestKey:p,res:e})})},function(e){if(!v)return Promise.reject(e);o({requestKey:p,err:e})});return v?a:m},Object.defineProperty(e,"__esModule",{value:!0})}); |
@@ -62,3 +62,4 @@ // This is a cache of in-flight requests. Each request key maps to an | ||
} else { | ||
throw new Error('dedupeOptions are required.'); | ||
opts = {}; | ||
initToUse = {}; | ||
} | ||
@@ -81,4 +82,3 @@ | ||
method: initToUse.method || input.method || '', | ||
body: initToUse.body || input.body || '', | ||
responseType: responseType | ||
body: initToUse.body || input.body || '' | ||
}); | ||
@@ -108,6 +108,14 @@ | ||
var request = fetch(input, initToUse).then(function (res) { | ||
var responseTypeToUse = void 0; | ||
if (responseType) { | ||
responseTypeToUse = responseType; | ||
} else if (res.status === 204) { | ||
responseTypeToUse = 'text'; | ||
} else { | ||
responseTypeToUse = 'json'; | ||
} | ||
// The response body is a ReadableStream. ReadableStreams can only be read a single | ||
// time, so we must handle that in a central location, here, before resolving | ||
// the fetch. | ||
return res[responseType]().then(function (data) { | ||
return res[responseTypeToUse]().then(function (data) { | ||
res.data = data; | ||
@@ -114,0 +122,0 @@ |
@@ -59,3 +59,4 @@ 'use strict'; | ||
} else { | ||
throw new Error('dedupeOptions are required.'); | ||
opts = {}; | ||
initToUse = {}; | ||
} | ||
@@ -72,4 +73,3 @@ | ||
method: initToUse.method || input.method || '', | ||
body: initToUse.body || input.body || '', | ||
responseType: responseType | ||
body: initToUse.body || input.body || '' | ||
}); | ||
@@ -99,6 +99,14 @@ | ||
const request = fetch(input, initToUse).then(res => { | ||
let responseTypeToUse; | ||
if (responseType) { | ||
responseTypeToUse = responseType; | ||
} else if (res.status === 204) { | ||
responseTypeToUse = 'text'; | ||
} else { | ||
responseTypeToUse = 'json'; | ||
} | ||
// The response body is a ReadableStream. ReadableStreams can only be read a single | ||
// time, so we must handle that in a central location, here, before resolving | ||
// the fetch. | ||
return res[responseType]().then(data => { | ||
return res[responseTypeToUse]().then(data => { | ||
res.data = data; | ||
@@ -105,0 +113,0 @@ |
{ | ||
"name": "fetch-dedupe", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "A thin wrapper around fetch that prevents duplicate requests.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -9,3 +9,3 @@ # Fetch Dedupe | ||
A (very) thin wrapper around | ||
[`global.fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) | ||
[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) | ||
that prevents duplicate requests. | ||
@@ -38,5 +38,5 @@ | ||
```js | ||
import { getRequestKey, fetchDedupe } from 'fetch-dedupe'; | ||
import { fetchDedupe } from 'fetch-dedupe'; | ||
const url = '/test/2'; | ||
const fetchOptions = { | ||
method: 'PATCH', | ||
@@ -49,3 +49,3 @@ body: JSON.stringify({ a: 12 }) | ||
// third argument | ||
fetchDedupe(url, fetchOptions, {responseType: 'json'}).then(res => { | ||
fetchDedupe('/test/2', fetchOptions).then(res => { | ||
console.log('Got some data', res.data); | ||
@@ -55,3 +55,3 @@ }); | ||
// Additional requests are deduped. Nifty. | ||
fetchDedupe(url, fetchOptions, {responseType: 'json'}).then(res => { | ||
fetchDedupe('/test/2', fetchOptions).then(res => { | ||
console.log('Got some data', res.data); | ||
@@ -74,3 +74,3 @@ }); | ||
// The same code using `fetchDedupe`: | ||
fetchDedupe(url, init, dedupeOptions) | ||
fetchDedupe(url, init) | ||
.then(res => | ||
@@ -81,3 +81,3 @@ console.log('got some cool data', res.data) | ||
// Don't do this! It will throw an error. | ||
fetchDedupe(url, init, dedupeOptions) | ||
fetchDedupe(url, init) | ||
.then(res => res.json()) | ||
@@ -96,3 +96,3 @@ .then(data => console.log('got some cool data', data)); | ||
##### `fetchDedupe( input [, init], dedupeOptions )` | ||
##### `fetchDedupe( input [, init] [, dedupeOptions] )` | ||
@@ -106,8 +106,10 @@ A wrapper around `global.fetch()`. The first two arguments are the same ones that you're used to. | ||
The third option is `dedupeOptions`. This is an object with three attributes: | ||
The third option is `dedupeOptions`, and it is also optional. This is an object with three attributes: | ||
* `responseType`: Any of the methods from [the Body mixin](https://developer.mozilla.org/en-US/docs/Web/API/Body). | ||
Typically, you will want to use `json`. Required. | ||
The default is `"json"`, unless the response status code is `"204"`, in which case `"text"` will be used to prevent | ||
an error. | ||
* `requestKey`: A string that is used to determine if two requests are identical. You may pass this | ||
to configure how the request key is generated. Optional. | ||
to configure how the request key is generated. A default key will be generated for you if this is | ||
omitted. | ||
* `dedupe`: Whether or not to dedupe the request. Pass `false` and it will be as if this library | ||
@@ -122,2 +124,10 @@ was not even being used. Defaults to `true`. | ||
// Omitting everything except for the URL | ||
fetchDedupe('/test/2'); | ||
// Just a URL and some init option | ||
fetchDedupe('/test/2', { | ||
method: 'DELETE' | ||
}); | ||
// Omitting `init` and using a URL string as `input` | ||
@@ -210,3 +220,3 @@ fetchDedupe('/test/2', {responseType: 'json'}); | ||
##### An empty response is throwing an error, what gives? | ||
##### An empty response body is throwing an error, what gives? | ||
@@ -221,9 +231,15 @@ Empty text strings are not valid JSON. | ||
Consequently, using `json` as the `responseType` when a response's body is empty will cause an | ||
Error to be thrown. To avoid this, we recommend using `text` instead. | ||
Error to be thrown. To avoid this, we recommend using `text` in these situations instead. | ||
APIs generally use empty bodies in conjunction with a 204 status code for responses | ||
of "write" requests (deletes, updates, and less commonly creates). | ||
of "write" requests (deletes, updates, and less commonly creates). For this reason, the default | ||
behavior of `responseType` is `"json"` except in situations when a 204 code is returned, in which | ||
case `"text"` will be used instead. | ||
##### Why is `responseType` required? | ||
If your API returns empty bodies with other codes, then you will need to manage that in your | ||
application. As a "worst-case scenario," you can always pass `"text"` and then try/catch a | ||
`JSON.parse` within a `.then()`. | ||
##### Why is `responseType` even an option? | ||
The argument that is returned to you in the `.then` callback of a call to `fetch()` is a | ||
@@ -253,2 +269,2 @@ [Response object](https://developer.mozilla.org/en-US/docs/Web/API/Response). The body of a Response | ||
[Apollo](https://www.apollographql.com/) inspired me to write this library. | ||
[Apollo](https://www.apollographql.com/) inspired me to write this library. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
25024
368
259