UNPKG

2.67 kBJavaScriptView Raw
1'use strict';
2
3const nodeFetch = require('node-fetch');
4const AppError = require('./appError');
5const { omitBy, isUndefined } = require('lodash');
6
7const omitUndefined = object => omitBy(object, isUndefined);
8
9const errorWith = (error, url, options, response, responseText) => {
10
11 let err = error;
12 if (!(err instanceof AppError)) {
13 err = new AppError(err.message);
14 }
15
16 err.setMeta(omitUndefined({
17 request: omitUndefined({ url, method: options.method || 'GET', body: options.body }),
18 response: response && {
19 status: response.status,
20 body: responseText
21 }
22 }));
23
24 return err;
25};
26
27/**
28 * @param {string} url
29 * @param {{
30 * expectOk?: boolean
31 * parseResponseAs?: 'json'|'text'
32 * }} [options] - extended Fetch options
33 * @returns {Promise.<nodeFetch.Response|string|*>}
34 *
35 * Returns Response object or parsed body value if parseResponseAs is specified
36 */
37async function fetch (url, options = {}) {
38
39 const {
40 expectOk = true,
41 parseResponseAs,
42 ...fetchOptions
43 } = options;
44
45 if (![undefined, 'json', 'text'].includes(parseResponseAs)) {
46 throw new Error('Invalid parseResponse option.');
47 }
48
49 let response;
50
51 try {
52 response = await nodeFetch(url, fetchOptions);
53
54 } catch (error) {
55 throw errorWith(error, url, options);
56 }
57
58 if (expectOk && !response.ok) {
59 const responseText = await response.text().catch(err => `RESPONSE BODY NOT PARSABLE: ${err}`);
60 throw errorWith(
61 new Error(`Response status ${response.status} is not ok`),
62 url,
63 options,
64 response,
65 responseText
66 );
67 }
68
69 if (!parseResponseAs) {
70 return response;
71 }
72
73 let responseText;
74 try {
75 responseText = await response.text();
76 } catch (err) {
77 throw errorWith(new Error('Response body is not parsable'), url, options, response);
78 }
79
80 if (parseResponseAs === 'text') {
81 return responseText;
82 }
83
84 try {
85 return JSON.parse(responseText);
86 } catch (error) {
87 throw errorWith(new Error('Response is not valid JSON'), url, options, response, responseText);
88 }
89}
90
91/**
92 * @param {string} url
93 * @param {Object} [options]
94 * @returns {Promise} Returns parsed JSON body
95 */
96fetch.json = async (url, options) => fetch(url, {
97 ...options,
98 parseResponseAs: 'json'
99});
100
101/**
102 * @param {string} url
103 * @param {Object} [options]
104 * @returns {Promise} Returns parsed text body
105 */
106fetch.text = async (url, options) => fetch(url, {
107 ...options,
108 parseResponseAs: 'text'
109});
110
111module.exports = fetch;