@tdb/util
Version:
Shared helpers and utilities.
110 lines (95 loc) • 2.3 kB
text/typescript
import { Subject } from 'rxjs';
import { share } from 'rxjs/operators';
import { IS_BROWSER } from '../../constants';
import { IHttpHeaders, IHttpResponse, HttpMethod, IHttpEvent } from './types';
import { time } from '../time';
import { id as idUtil } from '../id';
export * from './types';
if (IS_BROWSER) {
require('whatwg-fetch');
}
const _events$ = new Subject<IHttpEvent>();
export const events$ = _events$.pipe(share());
const DEFAULT_HEADERS = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
export async function request<T>(
method: HttpMethod,
url: string,
data?: any,
headers?: IHttpHeaders,
): Promise<IHttpResponse<T>> {
// Setup initial conditions.
const timer = time.timer();
const payload = {
method,
headers: new Headers({ ...DEFAULT_HEADERS, ...(headers || {}) }),
};
if (data) {
(payload as any).body = JSON.stringify(data);
}
// Fire pre-event.
const event: IHttpEvent = {
id: idUtil.shortid(),
stage: 'START',
method,
url,
data,
headers: payload.headers,
};
_events$.next(event);
// Make the request.
let ok = true;
let status = 200;
let statusText = 'OK';
let json: any;
let res: Response | undefined;
try {
res = await fetch(url, payload);
ok = res.ok;
status = res.status;
statusText = res.statusText;
} catch (err) {
ok = false;
status = 521;
statusText = 'CONNECTION_REFUSED';
}
// Parse the response JSON.
try {
json = res ? await res.json() : undefined;
} catch (error) {
// Ignore.
}
// Prepare the response.
const response: IHttpResponse<T> = {
ok,
status,
statusText,
elapsed: timer.elapsed(),
data: json as T,
};
// Finish up.
_events$.next({
...event,
stage: 'COMPLETE',
response,
});
return response;
}
/**
* Curry's a set of HTTP methods with the given HTTP headers.
*/
export function headers(headers: IHttpHeaders) {
return {
get: <T>(url: string) => {
return request<T>('GET', url, undefined, headers);
},
post: <T>(url: string, data: any) => {
return request<T>('POST', url, data, headers);
},
};
}
const DEFAULT_METHODS = headers({});
export const get = DEFAULT_METHODS.get;
export const post = DEFAULT_METHODS.post;