@rigil/apifetch
v2.0.0
Published
library wrapping fetch for easier usage
Downloads
68
Readme
apifetch
An API focused simplified fetch.
Install
$ npm i @rigil/apifetch
Basic usage
import api from '@rigil/apifetch'
// with import we get a default instance of the API
// we can change a few properties (see options paragraph)
api.setBaseURL('http://myserver.api/v1')
// and make requests, JSON by default
let allUSers = await api.get('users')
let oneUser = await api.get('users', {
email: '[email protected]'
})
// on POST requests the second argument is for the request body, the third
// the third will make aditional url parameters
let newUser = await api.post('users', {
email: '[email protected]',
password: 'secret'
})
await api.delete('users', { id: newUser.id })
Additional instances
But we can create new instances with specific options.
import { createApiInstance } from '@rigil/apifetch'
const codebergApi = createApiInstance({
baseURL: 'https://codeberg.org/api/v1'
})
export codebergApi
Options
The apifetch object uses a set of options for each instance. You can set there any fetch options, plus a few ones that are specific to apifetch:
| Option | Default | Description |
|--------|---------|-------------|
| baseURL | ''
| URL prefix for all requests |
| autoJson | true
| enables automatically converting data to JSON in requests and JSON to data in responses |
| cacheTime | DEFAULT_TIMEOUT
| enables cache feature using a timeout in milliseconds (0
will disable cache) |
| beforeRequest | []
| see Interceptors |
| afterResponse | []
| see Interceptors |
Methods
The first set of methods are to alter options after instance creation.
setBaseURL(baseURL)
It's the URL prefix used for all requests. Hence, the resource parameter in request calls can be relative to this prefix, and really represent a resource.
api.setBaseURL('https://codeberg.org/api/v1')
setAutoJson(enable)
If set, any request with a body, and if no Content-Type
header has been specified, will have the body converted to a JSON string.
In the other way, all responses with a Content-Type
matching /json/
will have their bodies converted to objects (or arrays)
If not enabled, the request requires a body as described by the fetch
API and the response will be the bare body as returned by fetch
.
setCacheTime(milliseconds)
For all GET
requests, a cache is maintained to avoid fetching the same data too quickly over the network. This cache is enabled by default to 1 second, but can be adjusted this way, or disabled with a cache time of 0
.
When data is cached for a specific URL, no network fetch is performed at all (unless a request interceptor is made to do it).
api.setCacheTime(0)
setAuthorization(token, type)
The Authorization
header can be automatically set for all requests to manage... authorization.
For this, you call this method with a token (or not to remove the authorization), and optionnaly a type which will be the header content prefix (defaults to Bearer
).
// enable authorization if mytoken is not null
api.setAuthorization(myToken) // Authorization: Bearer {myToken}
// set authorization to API client ID
api.setAuthorization(clientID, 'ClientID') // Authorization: ClientID {clientID}
// remove authorization header from all requests
api.setAuthorization()
api.setAuthorization(false) // same, more explicit
Request methods
Unlike fetch
you don't put query parameters in the URL directly (although you can if you want). The resource centric API style of apifetch separates the endpoint (base URL) from the resource denomination and its filtering through parameters.
The params parameter is an object containing query parameters (they all need to have a value, so myurl?isNotPossible
is not available).
It's not possible either to mix query parameters in the resource and params parameters. apifetch is dumb and will try to insert two ?
in the URL.
api.get(resource, params, additionalFetchOptions)
api.post(resource, body, params, additionalFetchOptions)
api.put(resource, body, params, additionalFetchOptions)
api.patch(resource, body, params, additionalFetchOptions)
api.delete(resource, params, additionalFetchOptions)
api.head(resource, params, additionalFetchOptions)
There is also a generic call where you can set your own method:
api.request(method, resource, params, body, additionalFetchOptions)
Interceptors
Interceptors permit to tweak requests and responses around fetch
calls, through the beforeRequest and afterResponse options, which should be arrays of functions.
In beforeRequest each request function receives the final url and options passed to fetch
and can either return:
- a
FetchParams
object containing modified url and options in its input and init properties respectively - a
Response
object, in which case process is stopped and this response is returned to caller (hint: that's how mock can be implemented)
import { FetchParams, createApiInstance } from 'apifetch'
const api = createApiInstance({
// ...
beforeRequest: [
// dummy request interceptor
async (url, options) => new FetchParams(url, options),
// shortcuting interceptor sending a response
async (url, options) => new Response('{}', {
status: 200,
statusText: 'I faked it!',
})
]
})
Likewise, after fetch
returns its response, this one can be altered with afterResponse interceptors with the request's url and options, plus a copy of the latest response (from fetch
or previous interceptor).
const api = createApiInstance({
// ...
afterResponse: [
// dummy response interceptor
async (url, options, response) => response
]
})
IMPORTANT
Interceptors must be inserted on the instance creation, or sent through requests options parameters. They can't be altered with methods.
But you can manage arrays yourself and modify them after giving them by reference, to get the same result.
const myRequestInterceptors = [
async (url, options) => new FetchParams(url, options)
]
const api = createApiInstance({
// ...
beforeRequest: myRequestInterceptors
})
myRequestInterceptors.push(
async (url, options) => new Response('{}', {
status: 200,
statusText: 'I faked it!',
})
)