UNPKG

x-http-client

Version:

An http client to make it easier to send requests (including JSONP requests) to the server.

526 lines (473 loc) 20.2 kB
var QS = require('x-query-string'); var merge = require('x-common-utils/merge'); var isFunction = require('x-common-utils/isFunction'); var isPlainObject = require('x-common-utils/isPlainObject'); var isAbsoluteURL = require('x-common-utils/isAbsoluteURL'); var uuid = require('../shared/uuid'); var noop = require('../shared/noop'); var template = require('../shared/template'); var inherits = require('../shared/inherits'); var constants = require('../shared/constants'); var defineExports = require('../shared/defineExports'); var createDefaultOptions = require('../shared/createDefaultOptions'); var createCancelController = require('../shared/createCancelController'); var Request = require('./Request'); var HttpRequest = require('./HttpRequest'); var JSONPRequest = require('./JSONPRequest'); var Response = require('./Response'); var HttpResponse = require('./HttpResponse'); var JSONPResponse = require('./JSONPResponse'); var ResponseError = require('./ResponseError'); var HttpResponseError = require('./HttpResponseError'); var JSONPResponseError = require('./JSONPResponseError'); var CancelController = require('./CancelController'); var version = '0.0.1-alpha.5'; /** * @class * * @param {RequestOptions} [defaults] The default options to use when sending requests with the created http client. * This default options will be merged into the internal default options that `createDefaultOptions()` returns. * * @param {HandleOptionsFunction} [handleDefaults] The handler function to process the merged default options. The * merged default options will be passed into the function as the first argument. You can make changes to it as you * want. This function must return synchronously. The return value of this function is ignored. * * @param {HandleOptionsFunction} [handleRequestOptions] The handler function to process each merged request options. * Every options that passed into `send`, `fetch`, `getJSONP`, `fetchJSONP` will be processed by this handler function. */ function HttpClient(defaults, handleDefaults, handleRequestOptions) { var defaultOptions = createDefaultOptions(); if (isPlainObject(defaults)) { merge(defaultOptions, defaults); } if (isFunction(handleDefaults)) { handleDefaults(defaultOptions); // Deep copy the chagned options defaultOptions = merge({}, defaultOptions); } if (!isFunction(handleRequestOptions)) { handleRequestOptions = noop; } /** * Get a copy of the default request options. This function is NOT available on the prototype of `HttpClient`. * * @returns {RequestOptions} */ this.copyOptions = function () { return merge({}, defaultOptions); }; /** * Merge the request options with the default request options. This function is NOT available on the prototype of * `HttpClient` and will call `handleRequestOptions` to handle the merged request options. * * @param {RequestOptions} options The request options to merge. * @returns {RequestOptions} Returns the merged request options. */ this.mergeOptions = function (options) { var requestOptions = merge({}, defaultOptions, options); handleRequestOptions(requestOptions); return requestOptions; }; } /** * Send an http request. * * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options. * @param {RequestSuccessCallback} onsuccess The callback to call on success. * @param {RequestErrorCallback} onerror The callback to call on error. * @returns {HttpRequest} Returns an instance of `HttpRequest`. */ HttpClient.prototype.send = function (options, onsuccess, onerror) { var requestOptions = this.mergeOptions(options); requestOptions.requestFunctionName = 'send'; requestOptions.controller = null; return new HttpRequest(requestOptions, onsuccess, onerror); }; /** * Send an http request and return a promise. * * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options. * @returns {Promise} Returns an instance of `Promise`. */ HttpClient.prototype.fetch = function (options) { var requestOptions = this.mergeOptions(options); var controller = requestOptions.controller; requestOptions.requestFunctionName = 'fetch'; return new Promise(function (resolve, reject) { var request = new HttpRequest(requestOptions, function (response) { if (controller) { if (!controller.isCancelled()) { resolve(response); } } else { resolve(response); } }, reject); if (controller) { // Trigger the `ERR_CANCELLED` error. if (controller.isCancelled()) { request.cancel(); } else { controller.registerCancelCallback(function () { request.cancel(); }); } } }); }; /** * Send a jsonp request. * * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options. * @param {RequestSuccessCallback} onsuccess The callback to call on success. * @param {RequestErrorCallback} onerror The callback to call on error. * @returns {JSONPRequest} Returns an instance of `JSONPRequest`. */ HttpClient.prototype.getJSONP = function (options, onsuccess, onerror) { var requestOptions = this.mergeOptions(options); requestOptions.requestFunctionName = 'getJSONP'; requestOptions.controller = null; return new JSONPRequest(requestOptions, onsuccess, onerror); }; /** * Send a jsonp request and return a promise. * * @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options. * @returns {Promise} Returns an instance of `Promise`. */ HttpClient.prototype.fetchJSONP = function (options) { var requestOptions = this.mergeOptions(options); var controller = requestOptions.controller; requestOptions.requestFunctionName = 'fetchJSONP'; return new Promise(function (resolve, reject) { var request = new JSONPRequest(requestOptions, function (response) { if (controller) { if (!controller.isCancelled()) { resolve(response); } } else { resolve(response); } }, reject); if (controller) { // Trigger the `ERR_CANCELLED` error. if (controller.isCancelled()) { request.cancel(); } else { controller.registerCancelCallback(function () { request.cancel(); }); } } }); }; /** * Create a new instance of `CancelController`. * * @returns {CancelController} Returns an new instance of `CancelController`. */ HttpClient.prototype.createCancelController = createCancelController; /** * Create a new instance of `CancelController`. * * @returns {CancelController} Returns an new instance of `CancelController`. */ HttpClient.createCancelController = createCancelController; // The version. HttpClient.version = version; HttpClient.prototype.version = version; defineExports(HttpClient, 'constants', merge({}, constants)); defineExports(HttpClient, 'libs', { QS: QS }); defineExports(HttpClient, 'classes', { CancelController: CancelController, HttpClient: HttpClient, HttpRequest: HttpRequest, HttpResponse: HttpResponse, HttpResponseError: HttpResponseError, JSONPRequest: JSONPRequest, JSONPResponse: JSONPResponse, JSONPResponseError: JSONPResponseError, Request: Request, Response: Response, ResponseError: ResponseError }); defineExports(HttpClient, 'functions', { template: template, merge: merge, isAbsoluteURL: isAbsoluteURL, isFunction: isFunction, isPlainObject: isPlainObject, uuid: uuid, noop: noop, inherits: inherits, createDefaultOptions: createDefaultOptions }); module.exports = HttpClient; /** * This callback is used to hanlde the merged request options. It must retrun the result synchronously. * * @callback HandleOptionsFunction * @param {RequestOptions} options The merged request options. * @returns {void} */ /** * The callback to call on success. * * @callback RequestSuccessCallback * @param {HttpResponse|any} response The http response or the return value of `options.transformResponse(response)`. */ /** * The callback to call on error. * * @callback RequestErrorCallback * @param {HttpResponseError|any} error The http response error or the return value of `options.transformError(error)`. */ /** * The definiton of the request options. * * @typedef {Object.<string, *>} RequestOptions * * @property {string} [method] The http request method. The default method is `GET`. * * @property {string} [baseURL] The request base url. If the `url` is relative url, and the `baseURL` is not `null`, the * `baseURL` will be prepend to the `url`. * * @property {string} url The request url that can contain any number of placeholders, and will be compiled with the * data that passed in with `options.model`. * * @property {Object.<string, *>} [model] The data used to compile the request url. * * @property {Object.<string, *>} [query] The data that will be compiled to query string. * * @property {Object.<string, *>} [body] The object that contains the content which will be send to the server. This * object has only one property. The name of the property is the content type of the content, which will be used to find * a processor in `options.httpRequestBodyProcessor`. The processor is used to process the value of the property. The * processed value which the processor returns will be send to the server as the request body. * * @property {number} [timeout] The number of milliseconds the request can take before it finished. If the timeout value * is `0`, no timer will be set. If the request does not finsihed within the given time, a timeout error will be thrown. * The default value is `0`. * * @property {boolean} [cors] Whether to set `withCredentials` property of the `XMLHttpRequest` to `true`. The default * value is `false`. * * @property {boolean} [noCache] Whether to disable the cache. If the value is `true`, the headers in * `options.noCacheHeaders` will be set. The default value is `false`. * * @property {Object.<string, *>} [noCacheHeaders] The headers to set when `options.noCache` is set to `true`. * * @property {string} [jsonp] The query string key to hold the value of the callback name when sending JSONP request. * The default values is `callback`. * * @property {Object.<string, *>} [settings] The object to keep the settings information that the user passed in. The * library itself will not touch this property. You can use this property to hold any information that you want, when * you extend the functionality of your own instance of `HttpClient`. The default value of this property is an empty * object. * * @property {Object.<string, *>} [headers] The object that contains the headers to set when sending the request. Only * the non-undefined and non-null headers are set. * * @property {CancelController} [controller] The `CancelController` used to cancel the request. It only works when using * `fetch` or `fetchJSONP` to send request. If the you send request using `send` or `getJSONP`, the `options.controller` * will be set to `null`. * * @property {string} [requestFunctionName] The name of the function that send the request. Can be `send`, `fetch`, * `getJSONP`, `fetchJSONP`. This value is set by the library, don't change it. * * @property {string} [requestType] The request type of this request. The value of it is set by the library itself, can * be `HTTP_REQUEST` or `JSONP_REQUEST`. Any other value the user passed in is ignored. You can use this property to get * the type of the current request. * * @property {Object.<string, *>} [xhrProps] The object that contains the properties to set on the instance of the * `XMLHttpRequest`. * * @property {string} [username] The user name to use for authentication purposes. The defualt value is `null`. * * @property {string} [password] The password to use for authentication purposes. The defualt value is `null`. * * @property {Object.<string, httpRequestBodyProcessor>} [httpRequestBodyProcessor] The object that contains the * http request body processors. * * @property {Object.<string, ResponseParseFunction>} [httpResponseParser] The object that contains the http response * parsers. * * @property {Object.<string, ResponseParseFunction>} [jsonpResponseParser] The object that contains the jsonp response * parsers. * * @property {Object.<string, ResponseErrorParseFunction>} [httpResponseErrorParser] The object that contains the http * response error parsers. * * @property {Object.<string, ResponseErrorParseFunction>} [jsonpResponseErrorParser] The object that contains the jsonp * response error parsers. * * @property {HanldeOptionsFunction} [handleOptions] The function to handle the options. * * @property {CreateXHRFunction} [createXHR] The function to create the `XMLHttpRequest` instance. * * @property {ScriptCreateFunction} [createScript] The function to create the `HTMLScriptElement` instance. * * @property {JSONPContainerFindFunction} [jsonpContainerNode] The function that returns the container node, which will * be used to append the script element when sending jsonp request. * * @property {JSONPCallbackNameGenerateFunction} [jsonpCallbackName] The function to generate the unique callback name * when sending jsonp request. * * @property {CompileURLFunction} [compileURL] The function to compile url. * * @property {EncodeQueryStringFunction} encodeQueryString The function to encode the query string. * * @property {XHRHookFunction} onXhrCreated The function to call on xhr created. * * @property {XHRHookFunction} onXhrOpened The functon to call on xhr opened. * * @property {XHRHookFunction} onXhrSent The function to call on xhr sent. * * @property {RequestCreatedFunction} onRequestCreated The function to call on request created. * * @property {CheckResponseOkFunction} isResponseOk The function to check whether the response is ok. * * @property {TransformErrorFunction} transformError The function to transfrom the response error. The return value of * this function will be passed to the `onerror` callback. * * @property {TransformResponseFunction} transformResponse The function to transfrom the response. The return value of * this function will be passed to the `onsuccess` callback. * * @property {CheckShouldCallErrorCallbackFunction} shouldCallErrorCallback The function to check whether to call the * error callback. * * @property {CheckShouldCallSuccessCallbackFunction} shouldCallSuccessCallback The function to check whether to call * the success callback. */ /** * The definiton of http request data processor. * * @typedef {Object.<string, *>} httpRequestBodyProcessor * @property {number} priority The priority of the processor. * @property {Object.<string, *>} [headers] The headers to set when this processor is used. * @property {HttpRequestContentProcessFunction} [processor] The function to process the request body. */ /** * The function to handle the options. * * @callback HanldeOptionsFunction * @param {RequestOptions} options The request options. */ /** * The function to process the request data. * * @callback HttpRequestContentProcessFunction * @param {Object.<string, *>} content The conent need to process. * @param {RequestOptions} options The request options of the current request. * @returns {any} Returns the value that will be send to the server. */ /** * The function to parse the response. This function will be mounted on the response instance, which made it a method * of the `Response` instance. The parameters and the return value is up on you. * * @callback ResponseParseFunction */ /** * The function to parse the response error. This function will be mounted on the response error instance, which made it * a method of the `ResponseError` instance. The parameters and the return value is up on you. * * @callback ResponseErrorParseFunction */ /** * The function to create the `XMLHttpRequest` instance. * * @callback CreateXHRFunction * @param {RequestOptions} options The request options. * @returns {XMLHttpRequest} Returns an instance of `XMLHttpRequest`. */ /** * The function to create the `HTMLScriptElement` instance. * * @callback ScriptCreateFunction * @param {RequestOptions} options The request options. * @returns {HTMLScriptElement} Returns an instance of `HTMLScriptElement`. */ /** * The function that returns the node to append the script element. * * @callback JSONPContainerFindFunction * @param {RequestOptions} options The request options. * @returns {Node} Returns the node to append the script element. */ /** * The function to generate the unique callback name. * * @callback JSONPCallbackNameGenerateFunction * @param {RequestOptions} options The request options. * @returns {string} Retruns a valid javascript identifier to hold the callbak. */ /** * The function to compile the request url. * * @callback CompileURLFunction * @param {string} url The url (with baseURL) to compile. * @param {Object.<string, *>} param The param to compile the url. * @param {RequestOptions} options The request options. * @returns {string} Returns the compiled url. */ /** * The function to encode the query string. * * @callback EncodeQueryStringFunction * @param {Object.<string, *>} data The data to be encoded to query string. * @param {RequestOptions} options The request options. * @returns {string} Returns the encoded query string. */ /** * The xhr hook function. * * @callback XHRHookFunction * @param {XMLHttpRequest} xhr The instance of `XMLHttpRequest`. * @param {RequestOptions} options The request options. */ /** * @callback RequestCreatedFunction * @param {HttpRequest|JSONPRequest} request The request instance, can be `HttpRequest` or `JSONPRequest`. */ /** * The function to check whether the response is ok. * * @callback CheckResponseOkFunction * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`. * @param {Response} response The response instance. * @returns {boolean} Returns `true` if the response is ok, otherwise `false` is returned. */ /** * The function to check whether to call the error callback. * * @callback CheckShouldCallErrorCallbackFunction * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`. * @param {any} transformedError The data that `options.transformError(...)` returns. * @param {HttpResponseError|JSONPResponseError} error The response error. */ /** * The function to check whether to call the success callback. * * @callback CheckShouldCallSuccessCallbackFunction * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`. * @param {any} transformedResponse The data that `options.transformResponse(...)` returns. * @param {HttpResponse|JSONPResponse} response The response. */ /** * The function to transfrom the response. The return value of this function will be passed to the `onsuccess` callback. * * @callback TransformResponseFunction * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`. * @param {HttpResponse|JSONPResponse} response The response. * @returns {any} Returns the transformed response. */ /** * The function to transfrom the response error. The return value of this function will be passed to the `onerror` * callback. * * @callback TransformErrorFunction * @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`. * @param {HttpResponseError|JSONPResponseError} error The response error. * @returns {any} Returns the transformed response error. */