UNPKG

mauss

Version:

practical functions and reusable configurations

79 lines (78 loc) 2.76 kB
/** * 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 }); }, }; }; }