Tiny wrapper around DOM fetch for common API wrappings. Isomorphic (supports browsers and Node.js), if fetch
is available or polyfilled.
yarn add @lcdev/fetch@VERSION
Features:
- Easy to use builder-style API
- Quick JSON, blob and text parsing options
- Shareable builders for common options (authorization headers, onResponse hooks, etc.)
- No magic - call
build()
and pass to fetch if you want - TypeScript friendly
- Tiny footprint (2kb)
If you are looking for something not available here, try ky-universal or axios.
There are two main functions exported by this package:
- The
apiCall
function, which is used for creating a one-off fetch request - The
api
function, which creates a shared builder for many fetch requests
The simplest function is apiCall
, which sets up a fetch request.
import { HttpMethod, apiCall } from '@lcdev/fetch';
await apiCall('https://base-url.com/endpoint', HttpMethod.GET).json<TheResponseObject>();
This can be shortened by using the http method aliases exported by this package.
import { get } from '@lcdev/fetch';
await get('https://base-url.com/endpoint').json<TheResponseObject>();
There are get
, post
, put
, patch
, and remove
aliases.
With a ApiCall
builder (the object returned by apiCall
), we can chain many options for the request.
withQuery(object, options?: SerializationOptions)
: adds query parameters, stringifying the object withquery-string
withHeaders(Headers)
: adds headers to requestwithHeader(key, value)
: adds a single header to the requestwithContentType(string)
: changes the content-type headerwithBearerToken(object: { token?: string })
: addsAuthorization: Bearer {token}
headerwithBody(object, isJson?: boolean, options?: SerializationOptions)
: adds a request bodywithJsonBody(object, options?: SerializationOptions)
: adds JSON request bodywithFormDataBody(FormData, options?: SerializationOptions)
: adds form-data request bodywithURLEncodedBody(object, options?: SerializationOptions)
: adds 'application/x-www-form-urlencoded' request bodywithExtraOptions(options: ExtraOptions)
: escape hatch to add extra options tofetch
while still using the builder patternexpectStatus(number)
: throw an error if the response status isn't the expected oneexpectSuccessStatus()
: throw an error if the response status isn't in 200 rangeonPreBuild(callback)
: calls your function before options are built for everyfetch
onResponse(callback)
: calls your function whenever responses are receivedonJsonResponse(callback)
: calls your function whenever JSON responses are receivedbuild()
: constructs options that can be passed intofetch
directlyjson<T>()
: calls fetch and parses response as JSONjsonAndResponse<T>()
: calls fetch and parses response as JSON, along with the full Response objectblob<T>()
: calls fetch and parses response as a blobblobAndResponse<T>()
: calls fetch and parses response as a blob, along with the full Response objecttext<T>()
: calls fetch and parses response as texttextAndResponse<T>()
: calls fetch and parses response as text, along with the full Response object
Because we expose build
, there is always an escape hatch if you need something non-standard.
Note that fetch calls are lazy - meaning that nothing will run until you call .then
or await
it.
Most of the time, we make web apps that call APIs many times in different ways (endpoints, authorization, etc.). This package provides a way to share configuration easily between all calls, without being "global".
import { api } from '@lcdev/fetch';
const myBackend = api('https://base-url.com')
.withBearerToken({ token: '...' })
.onResponse((res) => {
if (res.status === 401) logout();
});
// we can re-use myBackend where we want to
// you might put myBackend in a React Context, or inject it into state management
await myBackend.get('/endpoint').json<TheResponseObject>();
await myBackend.post('/endpoint').withJsonBody({ foo: 'bar' }).json<TheOtherResponse>();
Here, myBackend
is an Api
object, which exposes ways to create ApiCall
s (like above).
You can perform the same builder functions on these as with apiCall
.
You can add little callbacks to myBackend
using onResponse
or onJsonResponse
. You might
do this for logging, for business logic, etc.
You can change the base URL if required with changeBaseURL(path)
, though be warned that
every request from then on will then be based on that.
Just polyfill fetch
, and this package will work. Install cross-fetch
package and add the following to your main file.
yarn add cross-fetch@3
import fetch from 'cross-fetch';
import { setGlobalFetch } from '@lcdev/fetch';
setGlobalFetch(fetch);
Some API servers require a client TLS certificate to authenticate against their API.
In NodeJS, you can do this using a custom HTTPS agent that is aware of the client certificate.
Then you can use .withExtraOptions()
to pass the custom agent
to the fetch
options
Note: agent
is a non-standard option for node-fetch
.
import * as https from 'https';
const myApi = api('https://base-url.com')
.withBearerToken({ token: '...' })
.withExtraOptions({
agent: new https.Agent({
pfx: myPfxClientCertificate,
}),
});