Skip to content

Instantly share code, notes, and snippets.

@Mrtenz
Last active July 12, 2018 17:50
Show Gist options
  • Save Mrtenz/d4c0791ea060d7563d78f66e6938bb3c to your computer and use it in GitHub Desktop.
Save Mrtenz/d4c0791ea060d7563d78f66e6938bb3c to your computer and use it in GitHub Desktop.
Utility functions for interacting with a JSON API in TypeScript
/**
* Generate request data.
* @param {"POST" | "GET" | "DELETE" | "PUT" | "PATCH"} method
* @param body
* @return {{[key: string]: any}}
*/
const generateData = (method: 'POST' | 'GET' | 'DELETE' | 'PUT' | 'PATCH', body?: any): { [key: string]: any } => {
return {
method,
credentials: 'include',
headers: {
'Accepts': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
};
};
/**
* Generate a request.
* @param {string} path
* @param {"POST" | "GET" | "DELETE" | "PUT" | "PATCH"} method
* @param {Data} body
* @return {Promise<Data>}
*/
const generateRequest = <Data> (path: string, method: 'POST' | 'GET' | 'DELETE' | 'PUT' | 'PATCH', body?: Data): Promise<Data> => {
return new Promise<Data>((resolve, reject) => {
fetch(path, generateData(method, body))
.then(data => handleResponse<Data>(data))
.then(resolve)
.catch(reject);
});
};
/**
* Handle the response of a request. This assumes the response status code is 200 and throws an error otherwise.
* @param {Response} response
* @return {Promise<Data>}
*/
const handleResponse = async <Data> (response: Response): Promise<Data> => {
const json = await response.json();
if (response.status === 200) {
return json;
}
throw new Error(json.message);
};
/**
* Execute a HTTP GET request.
* @param {string} path
* @param params
* @returns {Promise<Data>}
*/
export const get = <Data = any> (path: string, params?: { [key: string]: string }): Promise<Data> => {
let queryString = '';
if (params) {
queryString = Object.keys(params).map(key => key + '=' + params[key]).join('&');
}
return generateRequest<Data>(`${path}${queryString}`, 'GET');
};
/**
* Execute a HTTP POST request.
* @param {string} path
* @param body
* @returns {Promise<Data>}
*/
export const post = <Data = any> (path: string, body?: any): Promise<Data> => {
return generateRequest<Data>(path, 'POST', body);
};
/**
* Execute a HTTP DELETE request.
* @param {string} path
* @param body
* @return {Promise<Data>}
*/
export const del = <Data = any> (path: string, body?: any): Promise<Data> => {
return generateRequest<Data>(path, 'DELETE', body);
};
/**
* Execute a HTTP PUT request.
* @param {string} path
* @param body
* @return {Promise<Data>}
*/
export const put = <Data = any> (path: string, body?: any): Promise<Data> => {
return generateRequest<Data>(path, 'PUT', body);
};
/**
* Execute a HTTP PATCH request.
* @param {string} path
* @param body
* @return {Promise<Data>}
*/
export const patch = <Data = any> (path: string, body?: any): Promise<Data> => {
return generateRequest<Data>(path, 'PATCH', body);
};
/**
* Wrapper for promises to make it easier to catch errors when using async/await.
*
* Example usage:
* const { error, data } = await to(getUsers());
* @type <T>
* @param {Promise<T>} promise
* @returns {Promise<{error?: Error, data?: T}>}
*/
export const to = <T> (promise: Promise<T>): Promise<{ error?: Error, data?: T }> => {
return promise
.then(data => ({
data
}))
.catch(error => ({
error
}));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment