mauss
Version:
practical functions and reusable configurations
79 lines (78 loc) • 2.76 kB
JavaScript
/**
* Fetcher factory to create a `send` function to make requests that abstracts the `fetch` API.
*
* @example
*
* ```javascript
* import { fetcher, type SendOptions } from 'mauss/api';
* const send = fetcher({
* prepare({ method, to, body }) {
* // ... do some checks or logging
* return {
* method: method || 'GET',
* mode: 'cors',
* credentials: 'include',
* headers: {
* 'Content-Type': 'application/json',
* },
* body: JSON.stringify(body),
* };
* },
* exit({ status }, payload) {
* if (status >= 500) return 'ServerError';
* if (status >= 400) return 'ClientError';
* // void or non-string means successful
* },
* });
* // use the `send` function above to make and export an abstraction
* export const API = {
* // use getter to determine the template and infer the defined parameters
* get 'session/:id'() {
* // `tsf` function from 'mauss/std'
* const render = tsf('https://auth.example/{id}/login');
* return (params: Parameters<typeof render>[0], options: SendOptions = {}) => {
* const target = send(render(params), options);
* return {
* // ... abstraction methods, for example
* async post() {
* return await target.post();
* },
* };
* };
* },
* };
* ```
*/
export function fetcher({ prepare = ({ method, body }) => ({ method, body: JSON.stringify(body) }), intercept = (url) => url, sweep = () => 'NetworkError: Please try again later.', transform = (r) => r.json().catch(() => ({})), exit = ({ ok }) => !ok && 'UnexpectedError: Try again later.', }) {
async function send({ headers, from, using, method, url, body, }) {
let response;
try {
const opts = prepare({ method, to: url, body, from, headers });
response = await (using || fetch)(intercept(url), opts);
}
catch (exception) {
return { error: sweep(exception) };
}
const payload = (await transform(response.clone()));
const error = await exit(response.clone(), payload);
if (error)
return { error };
return { data: payload };
}
return function http(url, options = {}) {
return {
get() {
return send({ method: 'GET', url, ...options });
},
post(payload) {
return send({ method: 'POST', url, body: payload, ...options });
},
put(payload) {
return send({ method: 'PUT', url, body: payload, ...options });
},
delete() {
return send({ method: 'DELETE', url, ...options });
},
};
};
}