@abalmus/request
Version:
Core utils, fetch wrapper, querystring utils
196 lines (153 loc) • 4.83 kB
text/typescript
import { encode } from '../utils/index';
import {
METHODS,
DEFAULT_OPTIONS
} from './constants';
import 'isomorphic-fetch';
import 'whatwg-fetch';
interface FetchOptionsI {
CSRFToken?: string;
headers?: object;
method?: string;
port?: number;
url: string;
}
function isObject(obj) {
return (typeof obj === 'object') && (obj !== null);
}
class FetchClient {
post?(url?: string): FetchClient;
get?(url?: string): FetchClient;
put?(url?: string): FetchClient;
delete?(url?: string): FetchClient;
private __request: any = {};
private __queryStringParams: any = '';
constructor(private options?: FetchOptionsI) {
this.__request = Object.assign({}, DEFAULT_OPTIONS, options);
METHODS.map(this.__createMethod.bind(this));
}
/* test-code */
__testApi() {
return this.__request
};
/* end-test-code */
public send(data: string | object): Promise<any> {
checkSubmissionData(data);
const { __request } = this;
const body = (
typeof data === 'string' ?
data :
encode(data)
);
return this.__doFetch(
this.__appendQueryString(__request.url),
Object.assign({}, __request, {body})
);
}
public sendJson(data: string| object): Promise<any> {
return this.send((
typeof data === 'string' ?
JSON.stringify(JSON.parse(data)) :
JSON.stringify(data)
));
}
public sendForm(form: HTMLFormElement) {
const formData = new FormData(form);
const { __request } = this;
return this.__doFetch(
form.action,
Object.assign({}, __request, {body: formData})
)
}
public query(query: string | object) {
checkSubmissionData(query);
if (isObject(query)) {
query = encode(query);
}
this.__queryStringParams = query;
return this;
}
public headers(field: string | object, value?: string) {
if (isObject(field)) {
for (let key in field as Object) {
if (Object.prototype.hasOwnProperty.call(field, key)) {
this.headers(key, field[key])
}
}
return this;
}
let existingHeaderName = this.hasHeader(field);
this.__request.headers[existingHeaderName || field] = value;
return this;
}
public hasHeader(name) {
let headers;
let lowercaseHeaders;
name = name.toLowerCase();
headers = Object.keys(this.__request.headers);
lowercaseHeaders = headers.map(header => {
return header.toLowerCase()
});
for (let i = 0; i < lowercaseHeaders.length; i++) {
if (lowercaseHeaders[i] === name) {
return headers[i]
}
}
return false
}
private __appendQueryString(url: string) {
if (url.split('?').length > 1) {
return `${url}&${this.__queryStringParams}`;
}
return (
this.__queryStringParams ?
`${url}?${this.__queryStringParams}` :
url
);
}
private __doFetch(url: string, options: RequestInit) {
return fetch(url, options)
.then(validateHttpResponse)
.catch(error => error);
}
private __applyMethodSpecificHeaders(method) {
switch(method) {
case 'POST':
!this.hasHeader('Content-Type') && this.headers({
'Content-Type': 'application/x-www-form-urlencoded'
});
break;
}
}
private __createMethod(method) {
this[method.toLowerCase()] = (url: string, port?: number) => {
if (!url && !this.__request.url) throw new Error(`Required parameter "url" in ${method.toLowerCase()} call is missed.`);
if (url) this.__request.url = url;
this.__request.method = method;
this.__applyMethodSpecificHeaders(method);
return this;
};
}
}
function validateHttpResponse(response) {
const { status, ok } = response;
if (status >= 400 || !ok) {
throw new Error(JSON.stringify({
status,
message: 'Bad response from server'
}));
}
return response;
}
function checkSubmissionData(data) {
if (!data || (!isObject(data) && typeof data !== 'string')) {
throw new Error('Data format is not correct please use object or string')
}
}
const json = (resp) => resp.json();
const text = (resp) => resp.text();
export const response = {
json,
text
}
export const request = (options?: FetchOptionsI) => new FetchClient(options);