@platform/http
Version:
Tools for working with HTTP.
155 lines (154 loc) • 5.04 kB
JavaScript
import { IS_PROD } from './constants';
import { Mime, value as valueUtil } from './libs';
export function stringify(data, errorMessage) {
try {
return data ? JSON.stringify(data) : '';
}
catch (err) {
let message = errorMessage();
message = !IS_PROD ? `${message} ${err.message}` : message;
throw new Error(message);
}
}
export function parseJson(args) {
const text = args.text;
try {
return (typeof text === 'string' && valueUtil.isJson(args.text)
? JSON.parse(text)
: text);
}
catch (error) {
const body = text ? text : '<empty>';
const msg = `Failed while parsing JSON for '${args.url}'.\nParse Error: ${error.message}\nBody: ${body}`;
throw new Error(msg);
}
}
export function toRawHeaders(input) {
const obj = Object.assign({}, (input || {}));
Object.keys(obj).forEach(key => {
obj[key] = obj[key].toString();
});
return new Headers(obj);
}
export function fromRawHeaders(input) {
const hasEntries = typeof input.entries === 'function';
const obj = hasEntries
? walkHeaderEntries(input)
: (input || {})._headers || {};
return Object.keys(obj).reduce((acc, key) => {
const value = Array.isArray(obj[key]) ? obj[key][0] : obj[key];
acc[key] = valueUtil.toType(value);
return acc;
}, {});
}
const walkHeaderEntries = (input) => {
var _a;
const res = {};
const entries = input.entries();
let next;
do {
next = entries.next();
if (next.value) {
const [key, value] = next.value;
res[key] = value;
}
} while (!((_a = next) === null || _a === void 0 ? void 0 : _a.done));
return res;
};
export function headerValue(key, headers = {}) {
key = key.trim().toLowerCase();
const match = Object.keys(headers)
.filter(k => k.trim().toLowerCase() === key)
.find(k => headers[k]) || '';
return match ? headers[match] : '';
}
export function isFormData(headers = {}) {
const contentType = headerValue('content-type', headers);
return contentType.includes('multipart/form-data');
}
export function isStream(value) {
var _a;
const stream = value;
return typeof ((_a = stream) === null || _a === void 0 ? void 0 : _a.pipe) === 'function';
}
export const response = {
async fromPayload(payload, modifications = {}) {
const { status, statusText = '' } = payload;
const data = payload.data || modifications.data;
let head = payload.headers || modifications.headers || {};
if (data && !headerValue('content-type', head)) {
head = Object.assign(Object.assign({}, head), { 'content-type': isStream(data) ? 'application/octet-stream' : 'application/json' });
}
const contentType = headerValue('content-type', head);
const isBinary = Mime.isBinary(contentType);
const toText = (data) => {
if (!data) {
return '';
}
if (typeof data === 'string') {
return data;
}
return stringify(data, () => `Failed while serializing data to JSON within [text] method.`);
};
const toJson = (data) => {
return data && !isBinary ? data : '';
};
let text = '';
let json = '';
const res = {
status,
statusText,
headers: toRawHeaders(head),
body: isBinary ? data : null,
async text() {
return text || (text = toText(data));
},
async json() {
return json || (json = toJson(data));
},
};
return response.fromFetch(res);
},
async fromFetch(res) {
const { status } = res;
const ok = status.toString()[0] === '2';
const body = res.body || undefined;
const statusText = res.statusText ? res.statusText : ok ? 'OK' : '';
const headers = fromRawHeaders(res.headers);
const contentType = response.toContentType(headers);
const text = contentType.is.text ? await res.text() : '';
const json = contentType.is.json ? await res.json() : '';
const result = {
ok,
status,
statusText,
headers,
contentType,
body,
text,
json,
};
return result;
},
toContentType(headers) {
const mime = headerValue('content-type', headers);
const res = {
mime,
is: {
get json() {
return Mime.isJson(mime);
},
get text() {
return Mime.isText(mime);
},
get binary() {
return Mime.isBinary(mime);
},
},
toString() {
return mime;
},
};
return res;
},
};