UNPKG

19.6 kBJavaScriptView Raw
1var merge = require('x-common-utils/merge');
2var isFunction = require('x-common-utils/isFunction');
3var isPlainObject = require('x-common-utils/isPlainObject');
4var noop = require('../shared/noop');
5var constants = require('../shared/constants');
6var createDefaultOptions = require('../shared/createDefaultOptions');
7var createCancelController = require('../shared/createCancelController');
8var Request = require('./Request');
9var HttpRequest = require('./HttpRequest');
10var JSONPRequest = require('./JSONPRequest');
11var Response = require('./Response');
12var HttpResponse = require('./HttpResponse');
13var JSONPResponse = require('./JSONPResponse');
14var ResponseError = require('./ResponseError');
15var HttpResponseError = require('./HttpResponseError');
16var JSONPResponseError = require('./JSONPResponseError');
17var CancelController = require('./CancelController');
18var version = '0.0.1-alpha.8';
19
20/**
21 * @class
22 *
23 * @param {RequestOptions} [defaults] The default options to use when sending requests with the created http client.
24 * This default options will be merged into the internal default options that `createDefaultOptions()` returns.
25 *
26 * @param {HandleOptionsFunction} [handleDefaults] The handler function to process the merged default options. The
27 * merged default options will be passed into the function as the first argument. You can make changes to it as you
28 * want. This function must return synchronously. The return value of this function is ignored.
29 *
30 * @param {HandleOptionsFunction} [handleRequestOptions] The handler function to process each merged request options.
31 * Every options that passed into `send`, `fetch`, `getJSONP`, `fetchJSONP` will be processed by this handler function.
32 */
33function HttpClient(defaults, handleDefaults, handleRequestOptions) {
34 var defaultOptions = createDefaultOptions();
35
36 if (isPlainObject(defaults)) {
37 merge(defaultOptions, defaults);
38 }
39
40 if (isFunction(handleDefaults)) {
41 handleDefaults(defaultOptions);
42 // Deep copy the chagned options
43 defaultOptions = merge({}, defaultOptions);
44 }
45
46 if (!isFunction(handleRequestOptions)) {
47 handleRequestOptions = noop;
48 }
49
50 /**
51 * Get a copy of the default request options. This function is NOT available on the prototype of `HttpClient`.
52 *
53 * @returns {RequestOptions}
54 */
55 this.copyOptions = function () {
56 return merge({}, defaultOptions);
57 };
58
59 /**
60 * Merge the request options with the default request options. This function is NOT available on the prototype of
61 * `HttpClient` and will call `handleRequestOptions` to handle the merged request options.
62 *
63 * @param {RequestOptions} options The request options to merge.
64 * @returns {RequestOptions} Returns the merged request options.
65 */
66 this.mergeOptions = function (options) {
67 var requestOptions = merge({}, defaultOptions, options);
68
69 handleRequestOptions(requestOptions);
70
71 return requestOptions;
72 };
73}
74
75/**
76 * Send an http request.
77 *
78 * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
79 * @param {RequestSuccessCallback} onsuccess The callback to call on success.
80 * @param {RequestErrorCallback} onerror The callback to call on error.
81 * @returns {HttpRequest} Returns an instance of `HttpRequest`.
82 */
83HttpClient.prototype.send = function (options, onsuccess, onerror) {
84 var requestOptions = this.mergeOptions(options);
85
86 requestOptions.requestFunctionName = 'send';
87 requestOptions.controller = null;
88
89 return new HttpRequest(requestOptions, onsuccess, onerror);
90};
91
92/**
93 * Send an http request and return a promise.
94 *
95 * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
96 * @returns {Promise} Returns an instance of `Promise`.
97 */
98HttpClient.prototype.fetch = function (options) {
99 var requestOptions = this.mergeOptions(options);
100 var controller = requestOptions.controller;
101
102 requestOptions.requestFunctionName = 'fetch';
103
104 return new Promise(function (resolve, reject) {
105 var request = new HttpRequest(requestOptions, function (response) {
106 if (controller) {
107 if (!controller.isCanceled()) {
108 resolve(response);
109 }
110 } else {
111 resolve(response);
112 }
113 }, reject);
114
115 if (controller) {
116 // Trigger the `ERR_CANCELED` error.
117 if (controller.isCanceled()) {
118 request.cancel();
119 } else {
120 controller.registerCancelCallback(function () {
121 request.cancel();
122 });
123 }
124 }
125 });
126};
127
128/**
129 * Send a jsonp request.
130 *
131 * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
132 * @param {RequestSuccessCallback} onsuccess The callback to call on success.
133 * @param {RequestErrorCallback} onerror The callback to call on error.
134 * @returns {JSONPRequest} Returns an instance of `JSONPRequest`.
135 */
136HttpClient.prototype.getJSONP = function (options, onsuccess, onerror) {
137 var requestOptions = this.mergeOptions(options);
138
139 requestOptions.requestFunctionName = 'getJSONP';
140 requestOptions.controller = null;
141
142 return new JSONPRequest(requestOptions, onsuccess, onerror);
143};
144
145/**
146 * Send a jsonp request and return a promise.
147 *
148 * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
149 * @returns {Promise} Returns an instance of `Promise`.
150 */
151HttpClient.prototype.fetchJSONP = function (options) {
152 var requestOptions = this.mergeOptions(options);
153 var controller = requestOptions.controller;
154
155 requestOptions.requestFunctionName = 'fetchJSONP';
156
157 return new Promise(function (resolve, reject) {
158 var request = new JSONPRequest(requestOptions, function (response) {
159 if (controller) {
160 if (!controller.isCanceled()) {
161 resolve(response);
162 }
163 } else {
164 resolve(response);
165 }
166 }, reject);
167
168 if (controller) {
169 // Trigger the `ERR_CANCELED` error.
170 if (controller.isCanceled()) {
171 request.cancel();
172 } else {
173 controller.registerCancelCallback(function () {
174 request.cancel();
175 });
176 }
177 }
178 });
179};
180
181/**
182 * Create a new instance of `CancelController`.
183 *
184 * @returns {CancelController} Returns an new instance of `CancelController`.
185 */
186HttpClient.prototype.createCancelController = createCancelController;
187
188/**
189 * Create a new instance of `CancelController`.
190 *
191 * @returns {CancelController} Returns an new instance of `CancelController`.
192 */
193HttpClient.createCancelController = createCancelController;
194
195// The version.
196HttpClient.version = HttpClient.prototype.version = version;
197
198// The exports.
199HttpClient.exports = HttpClient.prototype.exports = merge({
200 CancelController: CancelController,
201 HttpClient: HttpClient,
202 HttpRequest: HttpRequest,
203 HttpResponse: HttpResponse,
204 HttpResponseError: HttpResponseError,
205 JSONPRequest: JSONPRequest,
206 JSONPResponse: JSONPResponse,
207 JSONPResponseError: JSONPResponseError,
208 Request: Request,
209 Response: Response,
210 ResponseError: ResponseError,
211 createDefaultOptions: createDefaultOptions
212}, constants);
213
214module.exports = HttpClient;
215
216/**
217 * This callback is used to hanlde the merged request options. It must retrun the result synchronously.
218 *
219 * @callback HandleOptionsFunction
220 * @param {RequestOptions} options The merged request options.
221 * @returns {void}
222 */
223
224/**
225 * The callback to call on success.
226 *
227 * @callback RequestSuccessCallback
228 * @param {HttpResponse|any} response The http response or the return value of `options.transformResponse(response)`.
229 */
230
231/**
232 * The callback to call on error.
233 *
234 * @callback RequestErrorCallback
235 * @param {HttpResponseError|any} error The http response error or the return value of `options.transformError(error)`.
236 */
237
238/**
239 * The definiton of the request options.
240 *
241 * @typedef {Object.<string, *>} RequestOptions
242 *
243 * @property {string} [method] The http request method. The default method is `GET`.
244 *
245 * @property {string} [baseURL] The request base url. If the `url` is relative url, and the `baseURL` is not `null`, the
246 * `baseURL` will be prepend to the `url`.
247 *
248 * @property {string} url The request url that can contain any number of placeholders, and will be compiled with the
249 * data that passed in with `options.model`.
250 *
251 * @property {Object.<string, *>} [model] The data used to compile the request url.
252 *
253 * @property {Object.<string, *>} [query] The data that will be compiled to query string.
254 *
255 * @property {Object.<string, *>} [body] The object that contains the content which will be send to the server. This
256 * object has only one property. The name of the property is the content type of the content, which will be used to find
257 * a processor in `options.httpRequestBodyProcessor`. The processor is used to process the value of the property. The
258 * processed value which the processor returns will be send to the server as the request body.
259 *
260 * @property {number} [timeout] The number of milliseconds the request can take before it finished. If the timeout value
261 * is `0`, no timer will be set. If the request does not finsihed within the given time, a timeout error will be thrown.
262 * The default value is `0`.
263 *
264 * @property {boolean} [cors] Whether to set `withCredentials` property of the `XMLHttpRequest` to `true`. The default
265 * value is `false`.
266 *
267 * @property {boolean} [noCache] Whether to disable the cache. If the value is `true`, the headers in
268 * `options.noCacheHeaders` will be set. The default value is `false`.
269 *
270 * @property {Object.<string, *>} [noCacheHeaders] The headers to set when `options.noCache` is set to `true`.
271 *
272 * @property {string} [jsonp] The query string key to hold the value of the callback name when sending JSONP request.
273 * The default values is `callback`.
274 *
275 * @property {Object.<string, *>} [settings] The object to keep the settings information that the user passed in. The
276 * library itself will not touch this property. You can use this property to hold any information that you want, when
277 * you extend the functionality of your own instance of `HttpClient`. The default value of this property is an empty
278 * object.
279 *
280 * @property {Object.<string, *>} [headers] The object that contains the headers to set when sending the request. Only
281 * the non-undefined and non-null headers are set.
282 *
283 * @property {CancelController} [controller] The `CancelController` used to cancel the request. It only works when using
284 * `fetch` or `fetchJSONP` to send request. If the you send request using `send` or `getJSONP`, the `options.controller`
285 * will be set to `null`.
286 *
287 * @property {string} [requestFunctionName] The name of the function that send the request. Can be `send`, `fetch`,
288 * `getJSONP`, `fetchJSONP`. This value is set by the library, don't change it.
289 *
290 * @property {string} [requestType] The request type of this request. The value of it is set by the library itself, can
291 * be `HTTP_REQUEST` or `JSONP_REQUEST`. Any other value the user passed in is ignored. You can use this property to get
292 * the type of the current request.
293 *
294 * @property {Object.<string, *>} [xhrProps] The object that contains the properties to set on the instance of the
295 * `XMLHttpRequest`.
296 *
297 * @property {string} [username] The user name to use for authentication purposes. The defualt value is `null`.
298 *
299 * @property {string} [password] The password to use for authentication purposes. The defualt value is `null`.
300 *
301 * @property {Object.<string, httpRequestBodyProcessor>} [httpRequestBodyProcessor] The object that contains the
302 * http request body processors.
303 *
304 * @property {Object.<string, ResponseMixinFunction>} [httpResponseMixin] The object that contains the http response
305 * mixins.
306 *
307 * @property {Object.<string, ResponseMixinFunction>} [jsonpResponseMixin] The object that contains the jsonp response
308 * mixins.
309 *
310 * @property {Object.<string, ResponseErrorMixinFunction>} [httpResponseErrorMixin] The object that contains the http
311 * response error mixins.
312 *
313 * @property {Object.<string, ResponseErrorMixinFunction>} [jsonpResponseErrorMixin] The object that contains the jsonp
314 * response error mixins.
315 *
316 * @property {HanldeOptionsFunction} [handleOptions] The function to handle the options.
317 *
318 * @property {CreateXHRFunction} [createXHR] The function to create the `XMLHttpRequest` instance.
319 *
320 * @property {ScriptCreateFunction} [createScript] The function to create the `HTMLScriptElement` instance.
321 *
322 * @property {JSONPContainerFindFunction} [jsonpContainerNode] The function that returns the container node, which will
323 * be used to append the script element when sending jsonp request.
324 *
325 * @property {JSONPCallbackNameGenerateFunction} [jsonpCallbackName] The function to generate the unique callback name
326 * when sending jsonp request.
327 *
328 * @property {CompileURLFunction} [compileURL] The function to compile url.
329 *
330 * @property {EncodeQueryStringFunction} encodeQueryString The function to encode the query string.
331 *
332 * @property {XHRHookFunction} onXhrCreated The function to call on xhr created.
333 *
334 * @property {XHRHookFunction} onXhrOpened The functon to call on xhr opened.
335 *
336 * @property {XHRHookFunction} onXhrSent The function to call on xhr sent.
337 *
338 * @property {RequestCreatedFunction} onRequestCreated The function to call on request created.
339 *
340 * @property {CheckResponseOkFunction} isResponseOk The function to check whether the response is ok.
341 *
342 * @property {TransformErrorFunction} transformError The function to transfrom the response error. The return value of
343 * this function will be passed to the `onerror` callback.
344 *
345 * @property {TransformResponseFunction} transformResponse The function to transfrom the response. The return value of
346 * this function will be passed to the `onsuccess` callback.
347 *
348 * @property {CheckShouldCallErrorCallbackFunction} shouldCallErrorCallback The function to check whether to call the
349 * error callback.
350 *
351 * @property {CheckShouldCallSuccessCallbackFunction} shouldCallSuccessCallback The function to check whether to call
352 * the success callback.
353 */
354
355/**
356 * The definiton of http request data processor.
357 *
358 * @typedef {Object.<string, *>} httpRequestBodyProcessor
359 * @property {number} priority The priority of the processor.
360 * @property {Object.<string, *>} [headers] The headers to set when this processor is used.
361 * @property {HttpRequestContentProcessFunction} [processor] The function to process the request body.
362 */
363
364/**
365 * The function to handle the options.
366 *
367 * @callback HanldeOptionsFunction
368 * @param {RequestOptions} options The request options.
369 */
370
371/**
372 * The function to process the request data.
373 *
374 * @callback HttpRequestContentProcessFunction
375 * @param {Object.<string, *>} content The conent need to process.
376 * @param {RequestOptions} options The request options of the current request.
377 * @returns {any} Returns the value that will be send to the server.
378 */
379
380/**
381 * The function to parse the response. This function will be mounted on the response instance, which made it a method
382 * of the `Response` instance. The parameters and the return value is up on you.
383 *
384 * @callback ResponseMixinFunction
385 */
386
387/**
388 * The function to parse the response error. This function will be mounted on the response error instance, which made it
389 * a method of the `ResponseError` instance. The parameters and the return value is up on you.
390 *
391 * @callback ResponseErrorMixinFunction
392 */
393
394/**
395 * The function to create the `XMLHttpRequest` instance.
396 *
397 * @callback CreateXHRFunction
398 * @param {RequestOptions} options The request options.
399 * @returns {XMLHttpRequest} Returns an instance of `XMLHttpRequest`.
400 */
401
402/**
403 * The function to create the `HTMLScriptElement` instance.
404 *
405 * @callback ScriptCreateFunction
406 * @param {RequestOptions} options The request options.
407 * @returns {HTMLScriptElement} Returns an instance of `HTMLScriptElement`.
408 */
409
410/**
411 * The function that returns the node to append the script element.
412 *
413 * @callback JSONPContainerFindFunction
414 * @param {RequestOptions} options The request options.
415 * @returns {Node} Returns the node to append the script element.
416 */
417
418/**
419 * The function to generate the unique callback name.
420 *
421 * @callback JSONPCallbackNameGenerateFunction
422 * @param {RequestOptions} options The request options.
423 * @returns {string} Retruns a valid javascript identifier to hold the callbak.
424 */
425
426/**
427 * The function to compile the request url.
428 *
429 * @callback CompileURLFunction
430 * @param {string} url The url (with baseURL) to compile.
431 * @param {Object.<string, *>} param The param to compile the url.
432 * @param {RequestOptions} options The request options.
433 * @returns {string} Returns the compiled url.
434 */
435
436/**
437 * The function to encode the query string.
438 *
439 * @callback EncodeQueryStringFunction
440 * @param {Object.<string, *>} data The data to be encoded to query string.
441 * @param {RequestOptions} options The request options.
442 * @returns {string} Returns the encoded query string.
443 */
444
445/**
446 * The xhr hook function.
447 *
448 * @callback XHRHookFunction
449 * @param {XMLHttpRequest} xhr The instance of `XMLHttpRequest`.
450 * @param {RequestOptions} options The request options.
451 */
452
453/**
454 * @callback RequestCreatedFunction
455 * @param {HttpRequest|JSONPRequest} request The request instance, can be `HttpRequest` or `JSONPRequest`.
456 */
457
458/**
459 * The function to check whether the response is ok.
460 *
461 * @callback CheckResponseOkFunction
462 * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
463 * @param {Response} response The response instance.
464 * @returns {boolean} Returns `true` if the response is ok, otherwise `false` is returned.
465 */
466
467/**
468 * The function to check whether to call the error callback.
469 *
470 * @callback CheckShouldCallErrorCallbackFunction
471 * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
472 * @param {any} transformedError The data that `options.transformError(...)` returns.
473 * @param {HttpResponseError|JSONPResponseError} error The response error.
474 */
475
476/**
477 * The function to check whether to call the success callback.
478 *
479 * @callback CheckShouldCallSuccessCallbackFunction
480 * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
481 * @param {any} transformedResponse The data that `options.transformResponse(...)` returns.
482 * @param {HttpResponse|JSONPResponse} response The response.
483 */
484
485/**
486 * The function to transfrom the response. The return value of this function will be passed to the `onsuccess` callback.
487 *
488 * @callback TransformResponseFunction
489 * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
490 * @param {HttpResponse|JSONPResponse} response The response.
491 * @returns {any} Returns the transformed response.
492 */
493
494/**
495 * The function to transfrom the response error. The return value of this function will be passed to the `onerror`
496 * callback.
497 *
498 * @callback TransformErrorFunction
499 * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
500 * @param {HttpResponseError|JSONPResponseError} error The response error.
501 * @returns {any} Returns the transformed response error.
502 */