rest-api-handler
Version:
Handler for REST APIs
263 lines (223 loc) • 6.29 kB
JavaScript
import resolveProcessors from './resolveProcessors.js';
import * as dataFormats from './data-formats.js';
import { JSON as JSON$1, FORM_DATA, URL_ENCODED } from './data-formats.js';
/**
* Class for handling responses and requests.
*/
class Api {
/**
* Base api url
*/
/**
* Base http headers
*/
/**
* Base settings for Fetch Request
*/
/**
* List of processors that parse response from server.
*/
/**
* List of formatter you can use to process content of body request.
*/
/**
* Constructor.
*
* @param apiUrl - Base api url
* @param processors - List of processors that parse response from server.
* @param defaultHeaders - Base settings for Fetch Request
* @param defaultOptions - List of processors that parse response from server.
*/
constructor(apiUrl, processors = [], defaultHeaders = {}, defaultOptions = {}) {
this.apiUrl = apiUrl;
this.defaultHeaders = defaultHeaders;
this.defaultOptions = defaultOptions;
this.processors = processors;
}
/**
* Convert data in object to format of Fetch body.
*
* @param data - Data to convert
* @param to - Format to which convert the data. Default is JSON.
* @returns Converted data
*
* @example
* const body = Api.convertData({ a: 'b' }, Api.FORMATS.JSON);
* // output is {"a":"b"}
*/
static convertData(data, to = JSON$1) {
if (to === FORM_DATA) {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(key, value);
});
return formData;
}
if (to === URL_ENCODED) {
return Api.convertParametersToUrl(data).slice(1);
}
return JSON.stringify(data);
}
/**
* Convert object to url parameters string.
*
* @param parameters - List of parameters
* @returns Encoded string with ? prefix and variables separated by &
*
* @example
* const parameters = Api.convertData({ a: '%b%' });
* // output is ?a=%25b%25
*/
static convertParametersToUrl(parameters) {
const keys = Object.keys(parameters);
if (keys.length === 0) {
return '';
}
return `?${keys.map(key => {
return `${key}=${encodeURIComponent(parameters[key])}`;
}).join('&')}`;
}
/**
* Set default headers.
*
* @param headers - HTTP headers
*/
setDefaultHeaders(headers) {
this.defaultHeaders = headers;
}
/**
* Add default HTTP header.
*
* @param name - Name of header
* @param value - Value for header
* @example
* api.setDefaultHeader('content-type', 'application/json');
*/
setDefaultHeader(name, value) {
this.defaultHeaders[name] = value;
}
/**
* Remove default header.
*
* @param name - Name of header
*/
removeDefaultHeader(name) {
delete this.defaultHeaders[name];
}
/**
* Get default headers.
*
* @returns Get Default headers
*/
getDefaultHeaders() {
return this.defaultHeaders;
}
/**
* Fetch API url.
*
* @protected
* @param request - Fetch request
* @returns Fetch response
*/
fetchRequest(request) {
return fetch(request);
}
/**
* Request given API endpoint.
*
* @param namespace - Api endpoint or full url
* @param method - Request method eg. POST or GET
* @param options - Fetch options
* @param headers - Custom headers
* @returns processed response
* @example
* const { data } = await api.request('ad', 'POST', {
* body: '{"ad":1}'
* })
*
* const { data } = await api.request('http://i-can-request-full-url.com/?a=b', 'GET')
*/
async request(namespace, method, options = {}, headers = {}) {
const urlToRequest = namespace.indexOf('http') === 0 ? namespace : `${this.apiUrl}/${namespace}`; // eslint-disable-next-line compat/compat
const request = new Request(urlToRequest, { ...this.defaultOptions,
method,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line compat/compat
headers: new Headers({ ...this.getDefaultHeaders(),
...headers
}),
...options
});
const response = await this.fetchRequest(request);
return resolveProcessors(response, this.processors, request);
}
/**
* Send a request with body.
*
* @protected
* @param namespace - api endpoint
* @param method - api method
* @param data - body JSON parameters
* @param format - format of body request
* @param headers - custom headers
* @returns processed response
*/
requestWithBody(namespace, method, data, format, headers = {}) {
return this.request(namespace, method, {
body: Api.convertData(data, format)
}, headers);
}
/**
* Send a GET request.
*
* @param namespace - api endpoint
* @param parameters - get parameters
* @param headers - custom headers
* @returns processed response
*
* @example
* const { data } = await api.get('brand', { id: 5 })
* // will call YOUR_URI/brand?id=5
* console.log(data);
*/
get(namespace, parameters = {}, headers = {}) {
return this.request(`${namespace}${Api.convertParametersToUrl(parameters)}`, 'GET', {}, headers);
}
/**
* Send a POST request.
*
* @param namespace - Api endpoint
* @param data - Request object
* @param format - Format of body request
* @param headers - custom headers
* @returns Processed response
*/
post(namespace, data = {}, format = JSON$1, headers = {}) {
return this.requestWithBody(namespace, 'POST', data, format, headers);
}
/**
* Send a PUT request.
*
* @param namespace - Api endpoint
* @param data - Request object
* @param format - Format of body request
* @param headers - custom headers
* @returns Processed response
*/
put(namespace, data = {}, format = JSON$1, headers = {}) {
return this.requestWithBody(namespace, 'PUT', data, format, headers);
}
/**
* Send a DELETE request.
*
* @param namespace - Api endpoint
* @param headers - custom headers
* @returns Processed response
*/
delete(namespace, headers = {}) {
return this.request(namespace, 'DELETE', {}, headers);
}
}
Api.FORMATS = dataFormats;
export { Api as default };