
⛔️ DEPRECATED/UNMAINTAINED
[!CAUTION]
This project was ill-conceived, but taught me a lot about how I wanted to
structure my packages and other projects going forward.
Useful any time your project needs to consume JSON from some endpoint.
I love unfetch because it reminds me
of my dog it's such a lightweight no-nonsense fetch library. This package is a
small wrapper around unfetch geared specifically for fetching JSON and sharing
configuration across the application. Specifically:
- TypeScript support
- Default method is
POST (unless using SWR)
- Sugar functions for GET/POST/PUT/DELETE methods
content-type header is set to application/json
- Cookies are NOT sent along with the rest of the request (configurable)
- Request bodies can be anything serializable and will be stringified with
JSON.stringify
- Response bodies are automatically parsed with
JSON.parse
fetch() will not reject if a non-ok response is received (configurable)
- Simple differentiation between 2xx responses and non-2xx non-ok responses
- Exports functions to get and set app-wide configuration
- Sugar function for simple integration with
SWR
Install
npm install isomorphic-json-fetch
Quick start
import { fetch } from 'isomorphic-json-fetch'
const URL = 'api/endpoint';
let res, json, error;
({ json } = await fetch(URL));
doSomethingWith(json.myData);
try {
({ res, json } = await fetch.get<{ myData: number }>(URL));
if(!json) return handleErr(`response code outside 200-299: ${res.status}`);
doSomethingWith(json.myData);
}
catch(e) {
handleErr(`fetch failed: ${e}`);
}
const configuration = {
method: 'POST',
body: { query: 'some-string' }
};
try {
({ json, error } = await fetch<{ myData: number }, { message: string }>(URL, configuration));
if(error) return handleErr(error.message);
doSomethingWith(json.myData);
}
catch(e) {
handleErr(`fetch failed: ${e}`);
}
try { doSomethingWith((await fetch.post<{ myData: number }>(URL, { rejects: true })).json.myData) }
catch(e) {
handleErr(`fetch failed: ${e}`);
}
const { data, error } = useSwr(URL, fetch.swr);
if(error) return <div>failed to load</div>
if(!data) return <div>loading...</div>
return <div>hello #{data.myData}!</div>
Advanced usage
See unfetch for possible
configuration values. Additionally, you can add rejects: true to your config
to cause the promise returned by fetch() to reject on non-2xx HTTP responses.
By default, the promise returned by fetch() won't reject on HTTP error status
even if the response is an HTTP 404 or 500. Instead, it will resolve normally,
and it will only reject on network failure or if anything prevented the request
from completing. See
the unfetch docs for more
information.
For use with SWR, add swr: true to your
config and return a higher order function manually or just use the fetch.swr
sugar (see example above).
If you're using fetch() across many files in a more complex project, you can
set a global configuration once and it will be used by all fetch() calls
automatically:
import { fetch, setGlobalFetchConfig } from 'isomorphic-json-fetch'
const URL = 'api/endpoint';
setGlobalFetchConfig({
method: 'DELETE',
credentials: 'include',
});
let { json } = await fetch(URL);
({ json } = await fetch(URL, {
method: 'PUT',
}));
({ json } = await fetch(URL, { method: 'GET', ignoreParseErrors: true }));
json === undefined
({ json } = await fetch.get<'technically valid JSON', { error: string }>(URL));
import { fetch, unfetch } from 'isomorphic-json-fetch'
Instead of passing method choice through a configuration option, this package
provides several sugar functions:
import { fetch } from 'isomorphic-json-fetch'
const { json: get } = await fetch.get('/app?t=1');
const { json: post } = await fetch.post('/app?t=2', { body: { create: true }});
const { json: put } = await fetch.put('/app?t=3', { body: { newData: 'yes' }});
const { json: del } = await fetch.delete('/app?t=4');
Documentation
Documentation can be found under docs/ and can be built with
npm run build-docs.
Supporting and Contributing
New issues and pull requests are always welcome and greatly appreciated! 🤩
But that's not the only way to contribute! Just as well, you can star 🌟 this
project to let me know you found it useful! Thank you for your support ✊🏿
This repository uses a CI/CD
semantic-release
pipeline for vetting PRs and publishing releases. Be sure to
checkout the develop branch (not
main) and, when you're ready, fearlessly submit your PR against develop.
The pipeline will take care of the rest 🚀🚀🚀
NPM Scripts
Run npm run list-tasks locally to see which of the following scripts are
available for this project.
Using these scripts requires a linux-like development environment. None of the
scripts are likely to work on non-POSIX environments. If you're on Windows,
use WSL.
Development
npm run repl to run a buffered TypeScript-Babel REPL
npm test to run the unit tests and gather test coverage data
- Look for HTML files under
coverage/
npm run check-build to run the integration tests
npm run check-types to run a project-wide type check
npm run test-repeat to run the entire test suite 100 times
- Good for spotting bad async code and heisenbugs
- Uses
__test-repeat NPM script under the hood
npm run dev to start a development server or instance
npm run generate to transpile config files (under config/) from scratch
npm run regenerate to quickly re-transpile config files (under config/)
Building
npm run clean to delete all build process artifacts
npm run build to compile src/ into dist/, which is what makes it into
the published package
npm run build-docs to re-build the documentation
npm run build-externals to compile external-scripts/ into
external-scripts/bin/
npm run build-stats to gather statistics about Webpack (look for
bundle-stats.json)
Deploying
npm run start to start a production instance
NPX
npx sort-package-json to consistently sort package.json
npx npm-force-resolutions to forcefully patch security audit problems
Package Details
You don't need to read this section to use this package, everything should
"just work"!
This is a dual UMD (CJS2)/ES module package. That means this
package exposes both UMD+CJS2 and ESM entry points and can be used in most
JavaScript environments (browsers, any current or LTS Node version, etc).
Loading this package via require(...) will cause Node and modern browsers to
use the CJS2 bundle entry point, disable tree shaking in
Webpack 4, and lead to larger bundles in Webpack 5. Alternatively, loading this
package via import { ... } from ... or import(...) will cause Node and
modern browsers to use the ESM entry point in versions that support
it, in Webpack, and in the browser. Using the import syntax
is the modern, preferred choice.
For backwards compatibility with Webpack 4 and Node versions < 14,
package.json retains the module key, which
points to the ESM entry point, and the main key, which
points to both the ESM and CJS2 entry points implicitly (no file extension). For
Webpack 5 and Node versions >= 14, package.json includes the
exports key, which points to both entry points explicitly.
Though package.json includes
{ "type": "commonjs"}, note that the ESM entry points are ES
module (.mjs) files. package.json also includes the
sideEffects key, which is false for optimal tree
shaking, and the types key, which points to a TypeScript
declarations file.
This package does not maintain shared state and so does not exhibit the dual
package hazard. However, setting global configuration may not
actually be "globally" recognized by third-party code importing this package.