Skip to content

Instantly share code, notes, and snippets.

@belonog
Created December 12, 2021 13:33
Show Gist options
  • Save belonog/e8b526a7057b23caed544fa6d4243bb7 to your computer and use it in GitHub Desktop.
Save belonog/e8b526a7057b23caed544fa6d4243bb7 to your computer and use it in GitHub Desktop.
fetch data and format response
export function fetcher<T>(resource: RequestInfo, init: RequestInit = {}): Promise<T> {
return fetch(resource, {
...init,
credentials: 'include',
}).then(
(response) => {
return getJSON(response)
.catch((err) => {
throw new InternalError(err.message);
})
.then((json) => {
if (!response.ok) {
throw new ApiError(response.status, response.statusText, json);
}
return json;
});
},
(error) => {
throw new RequestError(error);
}
);
}
/**
* Error class for a custom `payload` or `meta` function throwing
*
* @class InternalError
* @access public
* @param {string} message - the error message
*/
export class InternalError extends Error {
name: 'InternalError';
message: string;
constructor(message: string) {
super();
this.name = 'InternalError';
this.message = message;
}
}
/**
* Error class for an error raised trying to make an API call
*
* @class RequestError
* @access public
* @param {string} message - the error message
*/
export class RequestError extends Error {
name: 'RequestError';
message: string;
constructor(message: string) {
super();
this.name = 'RequestError';
this.message = message;
}
}
/**
* Error class for an API response outside the 200 range
*
* @class ApiError
* @access public
* @param {number} status - the status code of the API response
* @param {string} statusText - the status text of the API response
* @param {object} response - the parsed JSON response of the API server if the
* 'Content-Type' header signals a JSON response
*/
export class ApiError<T = any> extends Error {
name: 'ApiError';
status: number;
statusText: string;
response: T;
message: string;
constructor(status: number, statusText: string, response: T) {
super();
this.name = 'ApiError';
this.status = status;
this.statusText = statusText;
this.response = response;
this.message = `${status} - ${statusText}`;
}
}
/**
* Extract JSON body from a server response
*
* @function getJSON
* @access public
* @param {object} res - A raw response object
* @returns {promise|undefined}
*/
async function getJSON(res: Response): Promise<any> {
const contentType = res.headers.get('Content-Type');
const emptyCodes = [204, 205];
if (emptyCodes.includes(res.status) === false && contentType && contentType.includes('json')) {
return await res.json();
} else {
return await Promise.resolve();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment