UNPKG

rest-boubou

Version:

RESTful HTTP client library

166 lines (142 loc) 5.71 kB
/* * Copyright 2012-2015 the original author or authors * @license MIT, see LICENSE.txt for details * * @author Scott Andrews */ (function (define) { 'use strict'; define(function (require) { var defaultClient, mixin, responsePromise, client, when; defaultClient = require('./client/default'); mixin = require('./util/mixin'); responsePromise = require('./util/responsePromise'); client = require('./client'); when = require('when'); /** * Interceptors have the ability to intercept the request and/org response * objects. They may augment, prune, transform or replace the * request/response as needed. Clients may be composed by wrapping * together multiple interceptors. * * Configured interceptors are functional in nature. Wrapping a client in * an interceptor will not affect the client, merely the data that flows in * and out of that client. A common configuration can be created once and * shared; specialization can be created by further wrapping that client * with custom interceptors. * * @param {Client} [target] client to wrap * @param {Object} [config] configuration for the interceptor, properties will be specific to the interceptor implementation * @returns {Client} A client wrapped with the interceptor * * @class Interceptor */ function defaultInitHandler(config) { return config; } function defaultRequestHandler(request /*, config, meta */) { return request; } function defaultResponseHandler(response /*, config, meta */) { return response; } function race(promisesOrValues) { // this function is different than when.any as the first to reject also wins return when.promise(function (resolve, reject) { promisesOrValues.forEach(function (promiseOrValue) { when(promiseOrValue, resolve, reject); }); }); } /** * Alternate return type for the request handler that allows for more complex interactions. * * @param properties.request the traditional request return object * @param {Promise} [properties.abort] promise that resolves if/when the request is aborted * @param {Client} [properties.client] override the defined client with an alternate client * @param [properties.response] response for the request, short circuit the request */ function ComplexRequest(properties) { if (!(this instanceof ComplexRequest)) { // in case users forget the 'new' don't mix into the interceptor return new ComplexRequest(properties); } mixin(this, properties); } /** * Create a new interceptor for the provided handlers. * * @param {Function} [handlers.init] one time intialization, must return the config object * @param {Function} [handlers.request] request handler * @param {Function} [handlers.response] response handler regardless of error state * @param {Function} [handlers.success] response handler when the request is not in error * @param {Function} [handlers.error] response handler when the request is in error, may be used to 'unreject' an error state * @param {Function} [handlers.client] the client to use if otherwise not specified, defaults to platform default client * * @returns {Interceptor} */ function interceptor(handlers) { var initHandler, requestHandler, successResponseHandler, errorResponseHandler; handlers = handlers || {}; initHandler = handlers.init || defaultInitHandler; requestHandler = handlers.request || defaultRequestHandler; successResponseHandler = handlers.success || handlers.response || defaultResponseHandler; errorResponseHandler = handlers.error || function () { // Propagate the rejection, with the result of the handler return when((handlers.response || defaultResponseHandler).apply(this, arguments), when.reject, when.reject); }; return function (target, config) { if (typeof target === 'object') { config = target; } if (typeof target !== 'function') { target = handlers.client || defaultClient; } config = initHandler(config || {}); function interceptedClient(request) { var context, meta; context = {}; meta = { 'arguments': Array.prototype.slice.call(arguments), client: interceptedClient }; request = typeof request === 'string' ? { path: request } : request || {}; request.originator = request.originator || interceptedClient; return responsePromise( requestHandler.call(context, request, config, meta), function (request) { var response, abort, next; next = target; if (request instanceof ComplexRequest) { // unpack request abort = request.abort; next = request.client || next; response = request.response; // normalize request, must be last request = request.request; } response = response || when(request, function (request) { return when( next(request), function (response) { return successResponseHandler.call(context, response, config, meta); }, function (response) { return errorResponseHandler.call(context, response, config, meta); } ); }); return abort ? race([response, abort]) : response; }, function (error) { return when.reject({ request: request, error: error }); } ); } return client(interceptedClient, target); }; } interceptor.ComplexRequest = ComplexRequest; return interceptor; }); }( typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } // Boilerplate for AMD and Node ));