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
JavaScript
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.
*/