127 lines
3.5 KiB
TypeScript
Raw Normal View History

import fetch from 'fetch';
import { apiErrorStatusMessage } from 'wherehows-web/constants/errors/errors';
import { ApiError, throwIfApiError } from 'wherehows-web/utils/api/errors/errors';
/**
* Describes the attributes on the fetch configuration object
*/
interface FetchConfig {
url: string;
2017-10-18 17:38:51 -07:00
headers?: { [key: string]: string } | Headers;
data?: object;
}
2018-01-18 18:52:42 -08:00
/**
* Describes the available options on an option bag to be passed into a fetch call
2018-01-18 18:52:42 -08:00
* @interface IFetchOptions
*/
interface IFetchOptions {
method?: string;
body?: any;
headers?: object | Headers;
credentials?: RequestCredentials;
}
2017-10-18 17:38:51 -07:00
/**
* Augments the user supplied headers with the default accept and content-type headers
* @param {FetchConfig.headers} headers
2017-10-18 17:38:51 -07:00
*/
const withBaseFetchHeaders = (headers: FetchConfig['headers']): { headers: FetchConfig['headers'] } => ({
headers: Object.assign(
{
Accept: 'application/json',
'Content-Type': 'application/json'
},
headers
)
2017-10-18 17:38:51 -07:00
});
/**
* Sends a HTTP request and resolves with the JSON response
* @template T
* @param {string} url the url for the endpoint to request a response from
* @param {object} fetchConfig
* @returns {Promise<T>}
2017-10-18 17:38:51 -07:00
*/
2018-01-18 18:52:42 -08:00
const json = <T>(url: string = '', fetchConfig: IFetchOptions = {}): Promise<T> =>
fetch(url, fetchConfig).then<T>(response => throwIfApiError(response));
2017-10-18 17:38:51 -07:00
/**
* Conveniently gets a JSON response using the fetch api
* @template T
* @param {FetchConfig} config
* @return {Promise<T>}
*/
const getJSON = <T>(config: FetchConfig): Promise<T> => {
const fetchConfig = { ...withBaseFetchHeaders(config.headers), method: 'GET' };
2017-10-18 17:38:51 -07:00
return json<T>(config.url, fetchConfig);
};
/**
* Initiates a POST request using the Fetch api
* @template T
* @param {FetchConfig} config
* @returns {Promise<T>}
2017-10-18 17:38:51 -07:00
*/
const postJSON = <T>(config: FetchConfig): Promise<T> => {
const requestBody = config.data ? { body: JSON.stringify(config.data) } : {};
2017-10-18 17:38:51 -07:00
const fetchConfig = Object.assign(
requestBody,
2017-10-18 17:38:51 -07:00
config.data && { body: JSON.stringify(config.data) },
withBaseFetchHeaders(config.headers),
2017-10-18 17:38:51 -07:00
{ method: 'POST' }
);
return json<T>(config.url, fetchConfig);
};
/**
* Initiates a DELETE request using the Fetch api
* @template T
* @param {FetchConfig} config
* @return {Promise<T>}
*/
2017-10-18 17:38:51 -07:00
const deleteJSON = <T>(config: FetchConfig): Promise<T> => {
const requestBody = config.data ? { body: JSON.stringify(config.data) } : {};
const fetchConfig = Object.assign(requestBody, withBaseFetchHeaders(config.headers), { method: 'DELETE' });
2017-10-18 17:38:51 -07:00
return json<T>(config.url, fetchConfig);
};
/**
* Initiates a PUT request using the Fetch api
* @template T
* @param {FetchConfig} config
* @return {Promise<T>}
*/
2017-10-18 17:38:51 -07:00
const putJSON = <T>(config: FetchConfig): Promise<T> => {
const requestBody = config.data ? { body: JSON.stringify(config.data) } : {};
const fetchConfig = Object.assign(requestBody, withBaseFetchHeaders(config.headers), { method: 'PUT' });
2017-10-18 17:38:51 -07:00
return json<T>(config.url, fetchConfig);
};
/**
* Requests the headers from a resource endpoint
* @param {FetchConfig} config
* @return {Promise<Headers>}
*/
const getHeaders = async (config: FetchConfig): Promise<Headers> => {
const fetchConfig = {
...withBaseFetchHeaders(config.headers),
2017-10-18 17:38:51 -07:00
method: 'HEAD'
};
const response = await fetch(config.url, fetchConfig);
const { ok, headers, status } = response;
if (ok) {
return headers;
}
throw new ApiError(status, apiErrorStatusMessage(status));
};
export { getJSON, postJSON, deleteJSON, putJSON, getHeaders };