x-ng2-http-interceptor
Version:
Adds interception capability around angular http api
395 lines • 18.5 kB
JavaScript
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
import { Headers, Http, RequestMethod } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/mergeMap';
import { InterceptorResponseWrapper } from './interceptor-response-wrapper';
import { InterceptorRequestBuilderInternal } from './interceptor-request-builder-internal';
import { InterceptorResponseWrapperBuilderInternal } from './interceptor-response-wrapper-builder-internal';
import { InterceptorUtils } from './interceptor-utils';
/**
* Wrapper around native angular `Http` service.
* Allows you to add `Interceptor`s that lets you do
* 1. Transform request before it reaches the actual request, such as, add headers transparently
* 2. Transform response, such as stripout the top level object & return the payload (or) raise errors if `response.status` is not `ok`
* 3. To short circuit the request flow based on runtime data
* 4. To selective caching/log request/responses
* 5. Augment the real `Observable<Response>` that native angular `http.request(..)` returns
* 6. Store intermediate data that can be shared across the interceptors
* 7. Generate handcrafted response incase of error/base of your runtime decision
*
* The service executes methods in the interceptor chain in the following manner
* 1. For each of the listed interceptor, tranforms the request by invoking\
* `beforeRequest(..)` on each interceptor in the same order they are added
* 2. Invokes native angular `http.request(..)` with the result of last interceptor's `beforeRequest(..)` response
* 3. Invokes `onResponse(..)` on each interceptor in the reverse order they are added
* 4. The response from `onResponse(..)` of the final interceptor in the chain would be sent to subscriber
*/
export var InterceptorService = (function (_super) {
__extends(InterceptorService, _super);
function InterceptorService(backend, defaultOptions) {
_super.call(this, backend, defaultOptions);
this.interceptors = [];
}
/** Parent overrides **/
InterceptorService.prototype.request = function (url, options) {
var interceptorOptions;
if (!options) {
interceptorOptions = {};
}
else if (this.representsInterceptorFlavor(options)) {
interceptorOptions = options;
}
else {
interceptorOptions = InterceptorUtils.from(options);
}
interceptorOptions.headers = interceptorOptions.headers || new Headers();
var request = InterceptorRequestBuilderInternal.new()
.url(url)
.options(interceptorOptions)
.sharedData(interceptorOptions.sharedData || {})
.build();
return this.httpRequest(request);
};
/**
* Performs a request with `get` http method.
*/
InterceptorService.prototype.get = function (url, options) {
options = options || {};
options.method = RequestMethod.Get;
options.url = options.url || url;
return this.request(url, options);
};
/**
* Performs a request with `post` http method.
*/
InterceptorService.prototype.post = function (url, body, options) {
options = options || {};
options.method = RequestMethod.Post;
options.url = options.url || url;
options.body = options.body || body;
return this.request(url, options);
};
/**
* Performs a request with `put` http method.
*/
InterceptorService.prototype.put = function (url, body, options) {
options = options || {};
options.method = RequestMethod.Put;
options.url = options.url || url;
options.body = options.body || body;
return this.request(url, options);
};
/**
* Performs a request with `delete` http method.
*/
InterceptorService.prototype.delete = function (url, options) {
options = options || {};
options.method = RequestMethod.Delete;
options.url = options.url || url;
return this.request(url, options);
};
/**
* Performs a request with `patch` http method.
*/
InterceptorService.prototype.patch = function (url, body, options) {
options = options || {};
options.method = RequestMethod.Patch;
options.url = options.url || url;
options.body = options.body || body;
return this.request(url, options);
};
/**
* Performs a request with `head` http method.
*/
InterceptorService.prototype.head = function (url, options) {
options = options || {};
options.method = RequestMethod.Head;
options.url = options.url || url;
return this.request(url, options);
};
/**
* Performs a request with `options` http method.
*/
InterceptorService.prototype.options = function (url, options) {
options = options || {};
options.method = RequestMethod.Options;
options.url = options.url || url;
return this.request(url, options);
};
/**
* Appends this interceptor to the list of interceptors
*/
InterceptorService.prototype.addInterceptor = function (interceptor) {
this.interceptors.push(interceptor);
};
Object.defineProperty(InterceptorService.prototype, "realResponseObservableTransformer", {
/**
* Sets response transformer
*/
set: function (value) {
this._realResponseObservableTransformer = value;
},
enumerable: true,
configurable: true
});
/** Private functions **/
InterceptorService.prototype.httpRequest = function (request) {
var _this = this;
return this.runBeforeInterceptors(request)
.flatMap(function (transformedRequest, _) {
var transformedRequestInternal = transformedRequest;
var interceptorRequestInternalBuilder = InterceptorRequestBuilderInternal.new(transformedRequestInternal);
if (interceptorRequestInternalBuilder.getErr() || interceptorRequestInternalBuilder.getAlreadyShortCircuited()) {
var responseWrapper = InterceptorResponseWrapperBuilderInternal
.newInternal(_this.interceptors.length, transformedRequestInternal)
.build();
return Observable.of(responseWrapper);
}
else if (interceptorRequestInternalBuilder.getShortCircuitAtCurrentStep()) {
var responseWrapper = InterceptorResponseWrapperBuilderInternal
.newInternal(_this.interceptors.length, transformedRequestInternal)
.build();
return Observable.of(responseWrapper);
}
var response$ = _super.prototype.request.call(_this, transformedRequest.url, transformedRequest.options);
if (_this._realResponseObservableTransformer) {
response$ = _this._realResponseObservableTransformer.transform(response$, transformedRequest, new _this.HttpDirect(), _this);
}
return response$.map(function (response) {
return InterceptorResponseWrapperBuilderInternal
.newInternal(_this.interceptors.length, transformedRequestInternal)
.response(response)
.build();
}).catch(function (err) {
var responseBuilder = InterceptorResponseWrapperBuilderInternal
.newInternal(_this.interceptors.length, transformedRequestInternal)
.err(err)
.errEncounteredAt(_this.interceptors.length)
.errEncounteredInRequestCycle(true);
return Observable.of(responseBuilder.build());
});
})
.flatMap(function (responseWrapper, index) {
return _this.runAfterInterceptors(responseWrapper);
})
.flatMap(function (responseWrapper, index) {
if (!responseWrapper.response) {
if (responseWrapper.err) {
return Observable.throw(responseWrapper.err);
}
else if (responseWrapper.isShortCircuited()) {
return Observable.throw(new Error('Short circuit was triggered, but no short circuit handlers generated any resonse'));
}
else {
return Observable.throw(new Error('Response is empty'));
}
}
return Observable.of(responseWrapper.response);
});
};
InterceptorService.prototype.runBeforeInterceptors = function (params) {
var request$ = Observable.of(params);
var _loop_1 = function(index) {
var interceptor = this_1.interceptors[index];
request$ = request$
.flatMap(function (request, _) {
var requestInternalBuilder = InterceptorRequestBuilderInternal.new(request);
if (requestInternalBuilder.getErr() || requestInternalBuilder.getAlreadyShortCircuited()) {
return Observable.of(request);
}
else if (requestInternalBuilder.getShortCircuitAtCurrentStep()) {
var requestBuilder = InterceptorRequestBuilderInternal.new(request)
.shortCircuitAtCurrentStep(false)
.shortCircuitTriggeredBy(index - 1) // since the last interceptor requested for short circuit
.alreadyShortCircuited(true);
return Observable.of(requestBuilder.build());
}
if (interceptor.beforeRequest !== undefined) {
var processedRequest = interceptor.beforeRequest(request, index);
var processedRequest$ = void 0;
if (!processedRequest) {
processedRequest$ = Observable.of(request);
}
else if (processedRequest instanceof Observable) {
processedRequest$ = processedRequest;
}
else {
processedRequest$ = Observable.of(processedRequest);
}
return processedRequest$
.catch(function (err, caught) {
var responseBuilder = InterceptorRequestBuilderInternal.new(request)
.err(err)
.errEncounteredAt(index);
return Observable.of(responseBuilder.build());
});
}
return Observable.of(request);
});
};
var this_1 = this;
for (var index = 0; index < this.interceptors.length; index++) {
_loop_1(index);
}
return request$;
};
InterceptorService.prototype.runAfterInterceptors = function (responseWrapper) {
var responseWrapper$ = Observable.of(responseWrapper);
var startFrom;
if (responseWrapper.err) {
startFrom = responseWrapper.errEncounteredAt;
}
else if (responseWrapper.isShortCircuited()) {
startFrom = responseWrapper.shortCircuitTriggeredBy;
}
else {
startFrom = this.interceptors.length - 1;
}
// If error occurred when making actual server call, lets start from last interceptor in the chain
if (startFrom === this.interceptors.length) {
startFrom = this.interceptors.length - 1;
}
var _loop_2 = function(index) {
var interceptor = this_2.interceptors[index];
responseWrapper$ = responseWrapper$
.flatMap(function (transformedResponseWrapper, _) {
if (transformedResponseWrapper.forceRequestCompletion) {
if (interceptor.onForceCompleteOrForceReturn !== undefined) {
interceptor.onForceCompleteOrForceReturn(transformedResponseWrapper, index);
}
if (index === 0) {
return Observable.empty();
}
else {
return Observable.of(transformedResponseWrapper);
}
}
else if (transformedResponseWrapper.forceReturnResponse) {
if (interceptor.onForceCompleteOrForceReturn !== undefined) {
interceptor.onForceCompleteOrForceReturn(transformedResponseWrapper, index);
}
return Observable.of(transformedResponseWrapper);
}
var processedResponse;
if (transformedResponseWrapper.err) {
if (interceptor.onErr !== undefined) {
processedResponse = interceptor.onErr(transformedResponseWrapper, index);
}
}
else if (transformedResponseWrapper.isShortCircuited()) {
if (interceptor.onShortCircuit !== undefined) {
processedResponse = interceptor.onShortCircuit(transformedResponseWrapper, index);
}
}
else if (interceptor.onResponse !== undefined) {
processedResponse = interceptor.onResponse(transformedResponseWrapper, index);
}
var procesedResponseWrapper$;
if (!processedResponse) {
procesedResponseWrapper$ = Observable.of(transformedResponseWrapper);
}
else if (processedResponse instanceof InterceptorResponseWrapper) {
procesedResponseWrapper$ = Observable.of(processedResponse);
}
else {
procesedResponseWrapper$ = processedResponse;
}
return procesedResponseWrapper$
.catch(function (err, __) {
var responseBuilder = InterceptorResponseWrapperBuilderInternal.newInternal(index, transformedResponseWrapper)
.err(err)
.errEncounteredAt(index)
.errEncounteredInRequestCycle(false);
return Observable.of(responseBuilder.build());
});
});
};
var this_2 = this;
for (var index = startFrom; index >= 0; index--) {
_loop_2(index);
}
return responseWrapper$;
};
/**
* Tests whether the passed in object represents interceptor version/native request options
*/
InterceptorService.prototype.representsInterceptorFlavor = function (options) {
return options.sharedData !== undefined
&& options.sharedData !== null;
};
Object.defineProperty(InterceptorService.prototype, "HttpDirect", {
/**
* Returns an implementation that mirrors angular `Http` interface;
* This interface allows the response transformers to make calls directly to HTTP calls
* without being interceted by {@code InterceptorService}; i.e `this`
*/
get: function () {
var interceptorService = this;
return (function () {
function class_1() {
}
class_1.prototype.request = function (url, options) {
return interceptorService.requestNative(url, options);
};
class_1.prototype.get = function (url, options) {
return interceptorService.getNative(url, options);
};
class_1.prototype.post = function (url, body, options) {
return interceptorService.postNative(url, body, options);
};
class_1.prototype.put = function (url, body, options) {
return interceptorService.putNative(url, body, options);
};
class_1.prototype.delete = function (url, options) {
return interceptorService.deleteNative(url, options);
};
class_1.prototype.patch = function (url, body, options) {
return interceptorService.patchNative(url, body, options);
};
class_1.prototype.head = function (url, options) {
return interceptorService.headNative(url, options);
};
class_1.prototype.options = function (url, options) {
return interceptorService.optionsNative(url, options);
};
return class_1;
}());
},
enumerable: true,
configurable: true
});
InterceptorService.prototype.requestNative = function (url, options) {
return _super.prototype.request.call(this, url, options);
};
InterceptorService.prototype.getNative = function (url, options) {
return _super.prototype.get.call(this, url, options);
};
InterceptorService.prototype.postNative = function (url, body, options) {
return _super.prototype.post.call(this, url, body, options);
};
InterceptorService.prototype.putNative = function (url, body, options) {
return _super.prototype.put.call(this, url, body, options);
};
InterceptorService.prototype.deleteNative = function (url, options) {
return _super.prototype.delete.call(this, url, options);
};
InterceptorService.prototype.patchNative = function (url, body, options) {
return _super.prototype.patch.call(this, url, body, options);
};
InterceptorService.prototype.headNative = function (url, options) {
return _super.prototype.head.call(this, url, options);
};
InterceptorService.prototype.optionsNative = function (url, options) {
return _super.prototype.options.call(this, url, options);
};
return InterceptorService;
}(Http));
//# sourceMappingURL=interceptor-service.js.map