@webex/http-core 3.0.0-beta.3 → 3.0.0-beta.300
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/http-error-subtypes.js +2 -147
- package/dist/http-error-subtypes.js.map +1 -1
- package/dist/http-error.js +9 -38
- package/dist/http-error.js.map +1 -1
- package/dist/index.js +54 -30
- package/dist/index.js.map +1 -1
- package/dist/interceptors/http-status.js +7 -30
- package/dist/interceptors/http-status.js.map +1 -1
- package/dist/lib/detect.js +28 -48
- package/dist/lib/detect.js.map +1 -1
- package/dist/lib/interceptor.js +7 -23
- package/dist/lib/interceptor.js.map +1 -1
- package/dist/lib/xhr.js +49 -93
- package/dist/lib/xhr.js.map +1 -1
- package/dist/progress-event.js +0 -7
- package/dist/progress-event.js.map +1 -1
- package/dist/request/index.js +3 -44
- package/dist/request/index.js.map +1 -1
- package/dist/request/request.js +5 -23
- package/dist/request/request.js.map +1 -1
- package/dist/request/request.shim.js +39 -91
- package/dist/request/request.shim.js.map +1 -1
- package/dist/request/utils.js +91 -0
- package/dist/request/utils.js.map +1 -0
- package/package.json +10 -10
- package/src/http-error-subtypes.js +1 -1
- package/src/http-error.js +15 -23
- package/src/index.js +59 -9
- package/src/interceptors/http-status.js +7 -5
- package/src/lib/detect.js +0 -1
- package/src/lib/interceptor.js +2 -4
- package/src/lib/xhr.js +201 -194
- package/src/progress-event.js +10 -5
- package/src/request/index.js +4 -36
- package/src/request/request.js +16 -14
- package/src/request/request.shim.js +51 -39
- package/src/request/utils.ts +78 -0
- package/test/integration/spec/http-error.js +11 -11
- package/test/integration/spec/interceptor.js +20 -13
- package/test/integration/spec/progress-event.js +8 -8
- package/test/integration/spec/request.js +136 -127
- package/test/unit/spec/index.js +58 -0
- package/test/unit/spec/interceptors/http-status.js +14 -11
- package/test/unit/spec/request/utils.js +77 -0
|
@@ -22,7 +22,15 @@ import detect from '../lib/detect';
|
|
|
22
22
|
*/
|
|
23
23
|
export default function _request(options) {
|
|
24
24
|
return new Promise((resolve) => {
|
|
25
|
-
const params = pick(
|
|
25
|
+
const params = pick(
|
|
26
|
+
options,
|
|
27
|
+
'method',
|
|
28
|
+
'uri',
|
|
29
|
+
'withCredentials',
|
|
30
|
+
'headers',
|
|
31
|
+
'timeout',
|
|
32
|
+
'responseType'
|
|
33
|
+
);
|
|
26
34
|
|
|
27
35
|
// Set `response` to `true` to approximate an `HttpResponse` object
|
|
28
36
|
params.response = true;
|
|
@@ -37,54 +45,64 @@ export default function _request(options) {
|
|
|
37
45
|
setPayload(params, options);
|
|
38
46
|
setQs(params, options);
|
|
39
47
|
|
|
40
|
-
options.logger.debug(
|
|
48
|
+
options.logger.debug(
|
|
49
|
+
`start http ${options.method ? options.method : 'request'} to ${options.uri}`
|
|
50
|
+
);
|
|
41
51
|
|
|
42
52
|
const x = xhr(params, (error, response) => {
|
|
43
53
|
/* istanbul ignore next */
|
|
44
54
|
if (error) {
|
|
45
|
-
options.logger.warn(
|
|
55
|
+
options.logger.warn(
|
|
56
|
+
`XHR error for ${options.method || 'request'} to ${options.uri} :`,
|
|
57
|
+
error
|
|
58
|
+
);
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
/* istanbul ignore else */
|
|
49
62
|
if (response) {
|
|
50
63
|
if (response.statusCode >= 400) {
|
|
51
|
-
options.logger.warn(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
options.logger.warn(
|
|
65
|
+
`http ${options.method ? options.method : 'request'} to ${options.uri} result: ${
|
|
66
|
+
response.statusCode
|
|
67
|
+
}`
|
|
68
|
+
);
|
|
69
|
+
} else {
|
|
70
|
+
options.logger.debug(
|
|
71
|
+
`http ${options.method ? options.method : 'request'} to ${options.uri} result: ${
|
|
72
|
+
response.statusCode
|
|
73
|
+
}`
|
|
74
|
+
);
|
|
55
75
|
}
|
|
56
76
|
response.options = options;
|
|
57
77
|
processResponseJson(response, params);
|
|
58
78
|
resolve(response);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
79
|
+
} else {
|
|
61
80
|
resolve({
|
|
62
81
|
statusCode: 0,
|
|
63
82
|
options,
|
|
64
83
|
headers: options.headers,
|
|
65
84
|
method: options.method,
|
|
66
85
|
url: options.uri,
|
|
67
|
-
body: error
|
|
86
|
+
body: error,
|
|
68
87
|
});
|
|
69
88
|
}
|
|
70
89
|
});
|
|
71
90
|
|
|
72
91
|
x.onprogress = options.download.emit.bind(options.download, 'progress');
|
|
73
|
-
})
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
});
|
|
92
|
+
}).catch((error) => {
|
|
93
|
+
options.logger.warn(error);
|
|
94
|
+
|
|
95
|
+
/* eslint arrow-body-style: [0] */
|
|
96
|
+
/* istanbul ignore next */
|
|
97
|
+
return {
|
|
98
|
+
statusCode: 0,
|
|
99
|
+
options,
|
|
100
|
+
headers: options.headers,
|
|
101
|
+
method: options.method,
|
|
102
|
+
url: options.uri,
|
|
103
|
+
body: error,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
88
106
|
|
|
89
107
|
/**
|
|
90
108
|
* @param {Object} params
|
|
@@ -121,8 +139,7 @@ export default function _request(options) {
|
|
|
121
139
|
if (o.auth) {
|
|
122
140
|
if (o.auth.bearer) {
|
|
123
141
|
params.headers.authorization = `Bearer ${o.auth.bearer}`;
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
142
|
+
} else {
|
|
126
143
|
const user = o.auth.user || o.auth.username;
|
|
127
144
|
const pass = o.auth.pass || o.auth.password;
|
|
128
145
|
|
|
@@ -157,7 +174,7 @@ export default function _request(options) {
|
|
|
157
174
|
// raynos/xhr defaults withCredentials to true if cors is true, so we need
|
|
158
175
|
// to make it explicitly false by default
|
|
159
176
|
withCredentials: false,
|
|
160
|
-
timeout: 0
|
|
177
|
+
timeout: 0,
|
|
161
178
|
};
|
|
162
179
|
|
|
163
180
|
defaults(params, pick(o, Object.keys(defs)), defs);
|
|
@@ -184,7 +201,7 @@ export default function _request(options) {
|
|
|
184
201
|
async function setContentType(params, o) {
|
|
185
202
|
if (o.body instanceof Blob || o.body instanceof ArrayBuffer) {
|
|
186
203
|
o.json = params.json = false;
|
|
187
|
-
params.headers['content-type'] = params.headers['content-type'] || await detect(o.body);
|
|
204
|
+
params.headers['content-type'] = params.headers['content-type'] || (await detect(o.body));
|
|
188
205
|
}
|
|
189
206
|
}
|
|
190
207
|
|
|
@@ -238,8 +255,7 @@ export default function _request(options) {
|
|
|
238
255
|
if (value.name) {
|
|
239
256
|
value.filename = value.name;
|
|
240
257
|
form.append(key, value, value.name);
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
258
|
+
} else {
|
|
243
259
|
form.append(key, value);
|
|
244
260
|
}
|
|
245
261
|
}
|
|
@@ -253,13 +269,11 @@ export default function _request(options) {
|
|
|
253
269
|
function setPayload(params, o) {
|
|
254
270
|
if ((!('json' in o) || o.json === true) && o.body) {
|
|
255
271
|
params.json = o.body;
|
|
256
|
-
}
|
|
257
|
-
else if (o.form) {
|
|
272
|
+
} else if (o.form) {
|
|
258
273
|
params.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
259
274
|
params.body = qs.stringify(o.form);
|
|
260
275
|
Reflect.deleteProperty(params, 'json');
|
|
261
|
-
}
|
|
262
|
-
else if (o.formData) {
|
|
276
|
+
} else if (o.formData) {
|
|
263
277
|
params.body = Object.keys(o.formData).reduce((fd, key) => {
|
|
264
278
|
const value = o.formData[key];
|
|
265
279
|
|
|
@@ -267,8 +281,7 @@ export default function _request(options) {
|
|
|
267
281
|
|
|
268
282
|
return fd;
|
|
269
283
|
}, new FormData());
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
284
|
+
} else {
|
|
272
285
|
params.body = o.body;
|
|
273
286
|
Reflect.deleteProperty(params, 'json');
|
|
274
287
|
}
|
|
@@ -286,8 +299,7 @@ export default function _request(options) {
|
|
|
286
299
|
if (!params.json && typeof response.body !== 'object') {
|
|
287
300
|
try {
|
|
288
301
|
response.body = JSON.parse(response.body);
|
|
289
|
-
}
|
|
290
|
-
catch (e) {
|
|
302
|
+
} catch (e) {
|
|
291
303
|
/* eslint no-empty: [0] */
|
|
292
304
|
}
|
|
293
305
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import {EventEmitter} from 'events';
|
|
3
|
+
import Interceptor from '../lib/interceptor';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} options
|
|
7
|
+
* @param {Array<Object>} interceptors
|
|
8
|
+
* @param {string} key
|
|
9
|
+
* @param {Object | undefined} res
|
|
10
|
+
* @private
|
|
11
|
+
* @returns {Promise}
|
|
12
|
+
*/
|
|
13
|
+
export function intercept(
|
|
14
|
+
options: object,
|
|
15
|
+
interceptors: Array<Interceptor>,
|
|
16
|
+
key: string,
|
|
17
|
+
res: object = undefined
|
|
18
|
+
): Promise<any> {
|
|
19
|
+
const successKey = `on${key}`;
|
|
20
|
+
const errorKey = `on${key}Error`;
|
|
21
|
+
|
|
22
|
+
return interceptors.reduce(
|
|
23
|
+
(promise, interceptor) =>
|
|
24
|
+
promise.then(
|
|
25
|
+
(result) => {
|
|
26
|
+
interceptor.logOptions(options);
|
|
27
|
+
if (interceptor[successKey]) {
|
|
28
|
+
return interceptor[successKey](options, result);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Promise.resolve(result);
|
|
32
|
+
},
|
|
33
|
+
(reason) => {
|
|
34
|
+
interceptor.logOptions(options);
|
|
35
|
+
if (interceptor[errorKey]) {
|
|
36
|
+
return interceptor[errorKey](options, reason);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return Promise.reject(reason);
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
Promise.resolve(res)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Prepare options for a fetch.
|
|
48
|
+
* @param {object} options
|
|
49
|
+
* @returns {Promise}
|
|
50
|
+
*/
|
|
51
|
+
export async function prepareFetchOptions(options: any): Promise<any> {
|
|
52
|
+
if (options.url) {
|
|
53
|
+
options.uri = options.url;
|
|
54
|
+
options.url = null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
options.headers = options.headers || {};
|
|
58
|
+
|
|
59
|
+
if (options.json) {
|
|
60
|
+
// don't override existing accept header declared by user
|
|
61
|
+
options.headers.accept = options.headers.accept || options.headers.Accept || 'application/json';
|
|
62
|
+
|
|
63
|
+
// don't override existing content-type header declared by user
|
|
64
|
+
if (options.method !== 'GET' && options.method !== 'HEAD') {
|
|
65
|
+
options.headers['content-type'] =
|
|
66
|
+
options.headers['content-type'] || options.headers['Content-Type'] || 'application/json';
|
|
67
|
+
options.body = JSON.stringify(options.json === true ? options.body : options.json);
|
|
68
|
+
}
|
|
69
|
+
} else if (options.json !== undefined) {
|
|
70
|
+
Reflect.deleteProperty(options, 'json');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
options.download = new EventEmitter();
|
|
74
|
+
options.upload = new EventEmitter();
|
|
75
|
+
options.keepalive = true;
|
|
76
|
+
|
|
77
|
+
return intercept(options, options.interceptors, 'Request').then(() => options);
|
|
78
|
+
}
|
|
@@ -71,7 +71,7 @@ describe('http-core', () => {
|
|
|
71
71
|
|
|
72
72
|
it('falls back to a default error message', () => {
|
|
73
73
|
const res = {
|
|
74
|
-
statusCode: 400
|
|
74
|
+
statusCode: 400,
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
const error = new HttpError(res);
|
|
@@ -83,7 +83,7 @@ describe('http-core', () => {
|
|
|
83
83
|
const message = 'an error occurred';
|
|
84
84
|
const res = {
|
|
85
85
|
statusCode: 400,
|
|
86
|
-
body: message
|
|
86
|
+
body: message,
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
const error = new HttpError(res);
|
|
@@ -93,12 +93,12 @@ describe('http-core', () => {
|
|
|
93
93
|
|
|
94
94
|
it('parses JSON responses', () => {
|
|
95
95
|
const message = {
|
|
96
|
-
data: 'an error'
|
|
96
|
+
data: 'an error',
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
const res = {
|
|
100
100
|
statusCode: 400,
|
|
101
|
-
body: message
|
|
101
|
+
body: message,
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
const error = new HttpError(res);
|
|
@@ -108,12 +108,12 @@ describe('http-core', () => {
|
|
|
108
108
|
|
|
109
109
|
it('parses stringified JSON responses', () => {
|
|
110
110
|
const message = JSON.stringify({
|
|
111
|
-
data: 'an error'
|
|
111
|
+
data: 'an error',
|
|
112
112
|
});
|
|
113
113
|
|
|
114
114
|
const res = {
|
|
115
115
|
statusCode: 400,
|
|
116
|
-
body: message
|
|
116
|
+
body: message,
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
const error = new HttpError(res);
|
|
@@ -126,8 +126,8 @@ describe('http-core', () => {
|
|
|
126
126
|
const res = {
|
|
127
127
|
statusCode: 400,
|
|
128
128
|
body: {
|
|
129
|
-
error: message
|
|
130
|
-
}
|
|
129
|
+
error: message,
|
|
130
|
+
},
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
const error = new HttpError(res);
|
|
@@ -141,9 +141,9 @@ describe('http-core', () => {
|
|
|
141
141
|
statusCode: 400,
|
|
142
142
|
body: {
|
|
143
143
|
error: {
|
|
144
|
-
errorString: message
|
|
145
|
-
}
|
|
146
|
-
}
|
|
144
|
+
errorString: message,
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
const error = new HttpError(res);
|
|
@@ -13,15 +13,21 @@ describe('http-core', () => {
|
|
|
13
13
|
describe('interceptor', () => {
|
|
14
14
|
let webex;
|
|
15
15
|
|
|
16
|
-
before('create users', () =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
before('create users', () =>
|
|
17
|
+
testUsers
|
|
18
|
+
.create({count: 1})
|
|
19
|
+
.then(
|
|
20
|
+
([user]) =>
|
|
21
|
+
new Promise((resolve) => {
|
|
22
|
+
setTimeout(() => resolve(user), 3000);
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
.then((user) => {
|
|
26
|
+
webex = new WebexCore({credentials: user.token});
|
|
27
|
+
})
|
|
28
|
+
.then(() => webex.internal.device.register())
|
|
29
|
+
.then(() => webex.internal.services.waitForCatalog('postauth', 10))
|
|
30
|
+
);
|
|
25
31
|
|
|
26
32
|
describe('logOptions', () => {
|
|
27
33
|
let flagged;
|
|
@@ -46,10 +52,11 @@ describe('http-core', () => {
|
|
|
46
52
|
it('calls logger plugin', () => {
|
|
47
53
|
const spy = sinon.spy(webex.logger, 'info');
|
|
48
54
|
|
|
49
|
-
return webex
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
return webex
|
|
56
|
+
.request({
|
|
57
|
+
service: 'hydra',
|
|
58
|
+
resource: 'people/me',
|
|
59
|
+
})
|
|
53
60
|
.then(() => {
|
|
54
61
|
assert.called(spy);
|
|
55
62
|
});
|
|
@@ -47,35 +47,35 @@ describe('http-core', () => {
|
|
|
47
47
|
{
|
|
48
48
|
loaded: undefined,
|
|
49
49
|
total: undefined,
|
|
50
|
-
result: false
|
|
50
|
+
result: false,
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
loaded: 10,
|
|
54
54
|
total: undefined,
|
|
55
|
-
result: false
|
|
55
|
+
result: false,
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
loaded: undefined,
|
|
59
59
|
total: 10,
|
|
60
|
-
result: false
|
|
60
|
+
result: false,
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
loaded: 10,
|
|
64
64
|
total: 10,
|
|
65
|
-
result: true
|
|
65
|
+
result: true,
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
loaded: 10,
|
|
69
69
|
total: 0,
|
|
70
|
-
result: false
|
|
70
|
+
result: false,
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
loaded: 0,
|
|
74
74
|
total: 0,
|
|
75
|
-
result: false
|
|
76
|
-
}
|
|
75
|
+
result: false,
|
|
76
|
+
},
|
|
77
77
|
].forEach((item) => {
|
|
78
|
-
assert.equal(
|
|
78
|
+
assert.equal(new ProgressEvent(item.loaded, item.total).lengthComputable, item.result);
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
81
|
});
|