1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const http = require('http');
|
12 | const https = require('https');
|
13 | const querystring = require('querystring');
|
14 | const { URL } = require('url');
|
15 |
|
16 | const ResponseType = Object.freeze({
|
17 | ArrayBuffer: Symbol('arraybuffer'),
|
18 | JSON: Symbol('json'),
|
19 | Text: Symbol('text'),
|
20 | Stream: Symbol('stream'),
|
21 | });
|
22 |
|
23 | const request = async ({
|
24 | uri,
|
25 | qs = null,
|
26 | responseType = ResponseType.JSON,
|
27 | body = null,
|
28 | method,
|
29 | headers,
|
30 | agent,
|
31 | }) => {
|
32 | const qsEnc = querystring.encode(qs);
|
33 | const completeUrl = new URL(uri + (qsEnc.length ? `?${qsEnc}` : ''));
|
34 |
|
35 | const reqOpts = {
|
36 | method,
|
37 | host: completeUrl.hostname,
|
38 | port: completeUrl.port,
|
39 | path: completeUrl.pathname + completeUrl.search + completeUrl.hash,
|
40 | headers,
|
41 | agent,
|
42 | };
|
43 |
|
44 | if (body) {
|
45 | reqOpts.headers['content-length'] = Buffer.byteLength(body);
|
46 | }
|
47 |
|
48 | const adapter = (completeUrl.protocol === 'https:') ? https : http;
|
49 |
|
50 | return new Promise((resolve, reject) => {
|
51 | const originalRequest = {
|
52 | ...reqOpts,
|
53 | body,
|
54 | };
|
55 |
|
56 | const req = adapter.request(reqOpts, (res) => {
|
57 | if (responseType === ResponseType.Stream) {
|
58 | return resolve({
|
59 | statusCode: res.statusCode,
|
60 | headers: res.headers,
|
61 | data: res,
|
62 | originalRequest,
|
63 | });
|
64 | }
|
65 | const data = [];
|
66 | res.on('data', (chunk) => data.push(chunk));
|
67 | res.on('end', () => {
|
68 | let result = Buffer.concat(data);
|
69 | if (responseType === ResponseType.Text || !result.length) {
|
70 | result = result.toString();
|
71 | } else if (responseType === ResponseType.JSON) {
|
72 | const contentType = res.headers['content-type'];
|
73 | if (!/^application\/json/.test(contentType)) {
|
74 | let err = new Error('Invalid content-type. ' +
|
75 | `Expected application/json but received ${contentType}`);
|
76 | err.originalRequest = originalRequest;
|
77 | return reject(err);
|
78 | }
|
79 | result = JSON.parse(result);
|
80 | }
|
81 | resolve({
|
82 | statusCode: res.statusCode,
|
83 | headers: res.headers,
|
84 | data: result,
|
85 | originalRequest,
|
86 | });
|
87 | });
|
88 | });
|
89 |
|
90 | req.on('error', (err) => {
|
91 | err.originalRequest = originalRequest;
|
92 | reject(err);
|
93 | });
|
94 |
|
95 | if (body) {
|
96 | req.write(body);
|
97 | }
|
98 | req.end();
|
99 | });
|
100 | };
|
101 |
|
102 | request.responseType = ResponseType;
|
103 |
|
104 | module.exports = request;
|