78 lines
2.4 KiB
JavaScript
Raw Normal View History

import { flow, fromPairs, get } from 'lodash';
import { map } from 'lodash/fp';
import { fromJS } from 'immutable';
import { fileExtension } from './path';
import unsentRequest from './unsentRequest';
2018-07-19 18:11:23 -07:00
export const filterByPropExtension = (extension, propName) => arr =>
arr.filter(el => fileExtension(get(el, propName)) === extension);
const catchFormatErrors = (format, formatter) => res => {
try {
return formatter(res);
} catch (err) {
throw new Error(
`Response cannot be parsed into the expected format (${format}): ${err.message}`,
);
2018-07-19 18:11:23 -07:00
}
};
const responseFormatters = fromJS({
json: async res => {
const contentType = res.headers.get('Content-Type');
if (!contentType.startsWith('application/json') && !contentType.startsWith('text/json')) {
throw new Error(`${contentType} is not a valid JSON Content-Type`);
2018-07-19 18:11:23 -07:00
}
return res.json();
},
text: async res => res.text(),
blob: async res => res.blob(),
}).mapEntries(([format, formatter]) => [format, catchFormatErrors(format, formatter)]);
2018-07-19 18:11:23 -07:00
export const parseResponse = async (res, { expectingOk = true, format = 'text' } = {}) => {
2018-07-19 18:11:23 -07:00
if (expectingOk && !res.ok) {
throw new Error(`Expected an ok response, but received an error status: ${res.status}.`);
2018-07-19 18:11:23 -07:00
}
const formatter = responseFormatters.get(format, false);
if (!formatter) {
throw new Error(`${format} is not a supported response format.`);
2018-07-19 18:11:23 -07:00
}
const body = await formatter(res);
return body;
};
export const responseParser = options => res => parseResponse(res, options);
export const parseLinkHeader = flow([
linksString => linksString.split(','),
map(str => str.trim().split(';')),
map(([linkStr, keyStr]) => [
keyStr.match(/rel="(.*?)"/)[1],
linkStr
.trim()
.match(/<(.*?)>/)[1]
.replace(/\+/g, '%20'),
]),
fromPairs,
]);
export const getPaginatedRequestIterator = (url, options = {}, linkHeaderRelName = 'next') => {
let req = unsentRequest.fromFetchArguments(url, options);
const next = async () => {
if (!req) {
return { done: true };
}
const pageResponse = await unsentRequest.performRequest(req);
const linkHeader = pageResponse.headers.get('Link');
const nextURL = linkHeader && parseLinkHeader(linkHeader)[linkHeaderRelName];
req = nextURL && unsentRequest.fromURL(nextURL);
return { value: pageResponse };
};
return {
[Symbol.asyncIterator]: () => ({
next,
}),
};
};