-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathapi.js
105 lines (90 loc) · 2.52 KB
/
api.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import fetch from 'node-fetch';
import https from 'https';
import _ from 'lodash';
import { loadConfig, defaults } from '../config.js';
const devHttpsAgent = new https.Agent({
rejectUnauthorized: false,
});
function getResponseContentType(response) {
const rawResponseContentType = response.headers.get('Content-Type');
const [contentType] = rawResponseContentType.split(';');
return contentType;
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export default async function api(options) {
const config = await loadConfig({ allowEmpty: true });
const isJson =
!options.path.includes('.js') && !options.path.includes('.css');
const fetchUrl = `${config.apiUrl}/v3${options.path}`;
const retryConfig = { retry: 3, pause: 5000 };
while (retryConfig.retry > 0) {
try {
const response = await fetch(
fetchUrl,
Object.assign(options, {
headers: {
...(isJson
? {
'Content-Type': 'application/json',
}
: {}),
...(config.token
? { Authorization: `Bearer ${config.token}` }
: {}),
...options.headers,
'x-raisely-cli': true,
},
body:
options.method !== 'GET' && options.json
? JSON.stringify(options.json)
: undefined,
agent: config.apiUrl ? devHttpsAgent : undefined,
})
);
const contentType = getResponseContentType(response);
const responseIsJSON = contentType === 'application/json';
const parseFormat = responseIsJSON ? 'json' : 'text';
const formatted = await response[parseFormat]();
if (response.status >= 399) {
const error = {
message: `${fetchUrl} (${
response.status
}) failed with message: ${
(responseIsJSON && formatted.detail) ||
response.statusText
}`,
status: response.status,
};
if (responseIsJSON && formatted) {
// if subcode, add this to error
const subcode = _.get(formatted, 'errors[0].subcode');
if (subcode) {
error.subcode = subcode;
}
}
throw error;
}
return formatted;
} catch (e) {
retryConfig.retry--;
// Handle MFA error
if (e.subcode && e.subcode.startsWith('MFA required')) {
throw e;
}
// Skip hard failures, except a timeout
if (e.status <= 500 && e.status !== 408) {
throw e.message;
}
// Retries exceeeded
if (retryConfig.retry === 0) {
throw e.message;
}
console.error('');
console.error(`An error occured, retrying... `);
console.error(`${e.message}`);
await sleep(retryConfig.pause);
}
}
}