├── .gitignore ├── .npmignore ├── README.md ├── index.d.ts ├── index.js ├── lib ├── intercepted-request.d.ts ├── intercepted-request.js ├── intercepted-request.js.map ├── intercepted-response.d.ts ├── intercepted-response.js ├── intercepted-response.js.map ├── interceptor-options.d.ts ├── interceptor-options.js ├── interceptor-options.js.map ├── interceptor-provider.d.ts ├── interceptor-provider.js ├── interceptor-provider.js.map ├── interceptor-service.d.ts ├── interceptor-service.js ├── interceptor-service.js.map ├── interceptor.d.ts ├── interceptor.js └── interceptor.js.map ├── package.json ├── src ├── intercepted-request.ts ├── intercepted-response.ts ├── interceptor-options.ts ├── interceptor-provider.ts ├── interceptor-service.ts ├── interceptor.ts └── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NG2-Interceptors 2 | 3 | This package adds the interceptor feature to Angular 2, by extending the @angular/http class. For concept behind Interceptor, take a look at the [wiki](https://github.com/voliva/angular2-interceptors/wiki/Concept) 4 | 5 | # Installation 6 | 7 | To install, just run in your angular project: 8 | 9 | ```javascript 10 | npm install ng2-interceptors --save 11 | ``` 12 | 13 | And it should be importable with webpack out of the box 14 | 15 | # Usage 16 | ## Set up InterceptorService 17 | Interceptors are registered when the service is created (to avoid any race-condition). To do so, you have to provide the instance of the service by yourself. So on your module declaration, you should put a provider like: 18 | 19 | ```javascript 20 | 21 | import { InterceptorService } from 'ng2-interceptors'; 22 | import { XHRBackend, RequestOptions } from '@angular/http'; 23 | 24 | export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions){ 25 | let service = new InterceptorService(xhrBackend, requestOptions); 26 | // Add interceptors here with service.addInterceptor(interceptor) 27 | return service; 28 | } 29 | 30 | @NgModule({ 31 | declarations: [ 32 | ... 33 | ], 34 | imports: [ 35 | ..., 36 | HttpModule 37 | ], 38 | providers: [ 39 | { 40 | provide: InterceptorService, 41 | useFactory: interceptorFactory, 42 | deps: [XHRBackend, RequestOptions] 43 | } 44 | ], 45 | bootstrap: [AppComponent] 46 | }) 47 | ``` 48 | 49 | There's a shorthand for this setup by using `provideInterceptorService`, but if you use AoT (Ahead-of-time) compilation it will fail. In fact, exporting the `interceptorFactory` is to make the AoT Compiler, as it needs all functions used in the provider to be exported. 50 | 51 | ```javascript 52 | 53 | import { provideInterceptorService } from 'ng2-interceptors'; 54 | 55 | @NgModule({ 56 | declarations: [ 57 | ... 58 | ], 59 | imports: [ 60 | ..., 61 | HttpModule 62 | ], 63 | providers: [ 64 | provideInterceptorService([ 65 | // Add interceptors here, like "new ServerURLInterceptor()" or just "ServerURLInterceptor" if it has a provider 66 | ]) 67 | ], 68 | bootstrap: [AppComponent] 69 | }) 70 | ``` 71 | 72 | ## Using InterceptorService 73 | Once we have it set up, we can use it in our Controllers as if we were using the default Angular `Http` service: 74 | ```javascript 75 | import { Component } from '@angular/core'; 76 | import { InterceptorService } from 'ng2-interceptors'; 77 | 78 | @Component({ 79 | selector: 'my-component', 80 | templateUrl: 'my-component.html', 81 | moduleId: 'my-module' 82 | }) 83 | export class MyComponent { 84 | 85 | constructor( 86 | private http: InterceptorService) { 87 | } 88 | 89 | ngOnInit(){ 90 | this.http.get("http://www.example.com/").subscribe( 91 | (res) => console.log(res), 92 | (err) => console.error(err), 93 | () => console.log("Yay")); 94 | } 95 | } 96 | ``` 97 | 98 | We can also "cheat" the Injector so that every time we ask for the `Http` we get the `InterceptorService` instead. All we have to do is replace `InterceptorService` on the provider definition for `Http`, and then we can get our service when we use `private http: Http`: 99 | 100 | ```javascript 101 | { 102 | provide: Http, 103 | useFactory: interceptorFactory, 104 | deps: [XHRBackend, RequestOptions] 105 | } 106 | ``` 107 | 108 | ## Creating your own Interceptor 109 | Basically, an interceptor is represented by one pair of functions: One that will get the request that's about to be sent to the server, and another that will get the response that the server just sent. For that, we just need to create a new class that implements Interceptor: 110 | 111 | ```javascript 112 | import { Interceptor, InterceptedRequest, InterceptedResponse } from 'ng2-interceptors'; 113 | 114 | export class ServerURLInterceptor implements Interceptor { 115 | public interceptBefore(request: InterceptedRequest): InterceptedRequest { 116 | // Do whatever with request: get info or edit it 117 | 118 | return request; 119 | /* 120 | You can return: 121 | - Request: The modified request 122 | - Nothing: For convenience: It's just like returning the request 123 | - (Observable.throw("cancelled")): Cancels the request, interrupting it from the pipeline, and calling back 'interceptAfter' in backwards order of those interceptors that got called up to this point. 124 | */ 125 | } 126 | 127 | public interceptAfter(response: InterceptedResponse): InterceptedResponse { 128 | // Do whatever with response: get info or edit it 129 | 130 | return response; 131 | /* 132 | You can return: 133 | - Response: The modified response 134 | - Nothing: For convenience: It's just like returning the response 135 | */ 136 | } 137 | } 138 | ``` 139 | 140 | Both methods are optional, so you can implement Interceptors that just take request or responses. 141 | 142 | Notice how there's a different object of `InterceptedRequest` and `InterceptedResponse`: They are modifications of angular's Http `Request` and `Response` needed for the whole Interceptor feature and to pass additional options that may be needed for specific interceptors (like to enable/disable them for specific calls, etc.) the API is: 143 | 144 | ```javascript 145 | interface InterceptedRequest { 146 | url: string, 147 | options?: RequestOptionsArgs, // Angular's HTTP Request options 148 | interceptorOptions?: any 149 | } 150 | interface InterceptedResponse { 151 | response: Response, // Angular's HTTP Response 152 | interceptorOptions?: any 153 | } 154 | ``` 155 | `interceptorOptions` on `InterceptedRequest` is guaranteed to be the same of that one of `InterceptedResponse` for the same call: The stuff you put in `interceptorOptions` while in `interceptBefore` will be available when you get `interceptAfter` called. 156 | 157 | ## Creating one Injectable Interceptor 158 | Interceptors are usually pure classes with pure functions: Given a call, they return a modified one, but sometimes we need these Interceptors to be actual Services to be used all around our application. 159 | 160 | For instance, an interceptor that shows a loading spinner every time we have a call has -in some way- to comunicate with the `LoadingComponent` to make the spinner appear/disappear from the screen. 161 | 162 | To do that you have to do some steps in the module/factory declaration file: 163 | 1. Create a Service (`@Injectable()` annotation) that implements `Interceptor` and the interceptor methods. 164 | 2. Define his provider before `InterceptorService` 165 | 3. Add it as a parameter to the factory function 166 | 4. Add it to the `deps` array. Note that the order of the elements have to match the one on the factory function. 167 | 5. Add it to the pipeline 168 | 169 | If you are using the `provideInterceptorService` option (without AoT Compiler support), then you can skip steps 2-4. 170 | 171 | If our `ServerURLInterceptor` were a Service, we would have a module declaration like: 172 | ```javascript 173 | import { InterceptorService } from 'ng2-interceptors'; 174 | import { ServerURLInterceptor } from './services/serverURLInterceptor'; 175 | import { XHRBackend, RequestOptions } from '@angular/http'; 176 | 177 | export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions, serverURLInterceptor:ServerURLInterceptor){ // Add it here 178 | let service = new InterceptorService(xhrBackend, requestOptions); 179 | service.addInterceptor(serverURLInterceptor); // Add it here 180 | return service; 181 | } 182 | 183 | @NgModule({ 184 | declarations: [ 185 | ... 186 | ], 187 | imports: [ 188 | ..., 189 | HttpModule 190 | ], 191 | providers: [ 192 | ServerURLInterceptor, // Add it here 193 | { 194 | provide: InterceptorService, 195 | useFactory: interceptorFactory, 196 | deps: [XHRBackend, RequestOptions, ServerURLInterceptor] // Add it here, in the same order as the signature of interceptorFactory 197 | } 198 | ], 199 | bootstrap: [AppComponent] 200 | }) 201 | ``` 202 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export { InterceptedRequest } from "./lib/intercepted-request"; 2 | export { InterceptedResponse } from "./lib/intercepted-response"; 3 | export { InterceptorOptions } from "./lib/interceptor-options"; 4 | export { InterceptorService } from "./lib/interceptor-service"; 5 | export { provideInterceptorService } from "./lib/interceptor-provider"; 6 | export { Interceptor } from "./lib/interceptor"; 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.InterceptorService = require('./lib/interceptor-service').InterceptorService; 2 | exports.provideInterceptorService = require('./lib/interceptor-provider').provideInterceptorService; 3 | -------------------------------------------------------------------------------- /lib/intercepted-request.d.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptionsArgs } from '@angular/http'; 2 | export interface InterceptedRequest { 3 | url: string; 4 | options?: RequestOptionsArgs; 5 | interceptorOptions?: any; 6 | } 7 | -------------------------------------------------------------------------------- /lib/intercepted-request.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //# sourceMappingURL=intercepted-request.js.map -------------------------------------------------------------------------------- /lib/intercepted-request.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"intercepted-request.js","sourceRoot":"","sources":["../src/intercepted-request.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /lib/intercepted-response.d.ts: -------------------------------------------------------------------------------- 1 | import { Response } from '@angular/http'; 2 | export interface InterceptedResponse { 3 | response: Response; 4 | intercepted?: Boolean; 5 | interceptorStep?: number; 6 | interceptorOptions?: any; 7 | } 8 | -------------------------------------------------------------------------------- /lib/intercepted-response.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //# sourceMappingURL=intercepted-response.js.map -------------------------------------------------------------------------------- /lib/intercepted-response.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"intercepted-response.js","sourceRoot":"","sources":["../src/intercepted-response.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /lib/interceptor-options.d.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptionsArgs } from '@angular/http'; 2 | export interface InterceptorOptions extends RequestOptionsArgs { 3 | interceptorOptions?: any; 4 | } 5 | -------------------------------------------------------------------------------- /lib/interceptor-options.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //# sourceMappingURL=interceptor-options.js.map -------------------------------------------------------------------------------- /lib/interceptor-options.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"interceptor-options.js","sourceRoot":"","sources":["../src/interceptor-options.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /lib/interceptor-provider.d.ts: -------------------------------------------------------------------------------- 1 | import { FactoryProvider } from '@angular/core'; 2 | export declare function provideInterceptorService(interceptors: any[]): FactoryProvider; 3 | -------------------------------------------------------------------------------- /lib/interceptor-provider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var http_1 = require("@angular/http"); 3 | var interceptor_service_1 = require("./interceptor-service"); 4 | function provideInterceptorService(interceptors) { 5 | var deps = [ 6 | http_1.XHRBackend, 7 | http_1.RequestOptions 8 | ]; 9 | interceptors = interceptors.map(function (interceptor) { 10 | if (typeof interceptor == "function") { 11 | deps.push(interceptor); 12 | return { 13 | useValue: false, 14 | index: deps.length - 1 15 | }; 16 | } 17 | else { 18 | return { 19 | useValue: interceptor 20 | }; 21 | } 22 | }); 23 | return { 24 | provide: interceptor_service_1.InterceptorService, 25 | useFactory: function () { 26 | var injectedServices = arguments; 27 | var xhrBackend = injectedServices[0]; 28 | var requestOptions = injectedServices[1]; 29 | var service = new interceptor_service_1.InterceptorService(xhrBackend, requestOptions); 30 | interceptors.forEach(function (interceptor) { 31 | if (interceptor.useValue) { 32 | service.addInterceptor(interceptor.useValue); 33 | } 34 | else { 35 | var value = injectedServices[interceptor.index]; 36 | service.addInterceptor(value); 37 | } 38 | }); 39 | return service; 40 | }, 41 | deps: deps, 42 | multi: false 43 | }; 44 | } 45 | exports.provideInterceptorService = provideInterceptorService; 46 | //# sourceMappingURL=interceptor-provider.js.map -------------------------------------------------------------------------------- /lib/interceptor-provider.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"interceptor-provider.js","sourceRoot":"","sources":["../src/interceptor-provider.ts"],"names":[],"mappings":";AACA,sCAA2D;AAC3D,6DAA2D;AAE3D,mCAA0C,YAAkB;IAC3D,IAAI,IAAI,GAAS;QAChB,iBAAU;QACV,qBAAc;KACd,CAAC;IAEF,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,UAAC,WAAe;QAC/C,EAAE,CAAA,CAAC,OAAO,WAAW,IAAI,UAAU,CAAC,CAAA,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvB,MAAM,CAAC;gBACN,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,IAAI,CAAC,MAAM,GAAC,CAAC;aACpB,CAAA;QACF,CAAC;QAAA,IAAI,CAAA,CAAC;YACL,MAAM,CAAC;gBACN,QAAQ,EAAE,WAAW;aACrB,CAAA;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC;QACN,OAAO,EAAE,wCAAkB;QAC3B,UAAU,EAAE;YACX,IAAI,gBAAgB,GAAG,SAAS,CAAC;YACjC,IAAI,UAAU,GAAc,gBAAgB,CAAC,CAAC,CAAC,CAAC;YAChD,IAAI,cAAc,GAAkB,gBAAgB,CAAC,CAAC,CAAC,CAAC;YAExD,IAAI,OAAO,GAAG,IAAI,wCAAkB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;YACjE,YAAY,CAAC,OAAO,CAAC,UAAC,WAAW;gBAChC,EAAE,CAAA,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA,CAAC;oBACxB,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC9C,CAAC;gBAAA,IAAI,CAAA,CAAC;oBACL,IAAI,KAAK,GAAG,gBAAgB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;oBAChD,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACF,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,CAAC;QAChB,CAAC;QACD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK;KACZ,CAAA;AACF,CAAC;AAzCD,8DAyCC"} -------------------------------------------------------------------------------- /lib/interceptor-service.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectionBackend, Http, Request, Response, RequestOptions } from '@angular/http'; 2 | import { Observable } from 'rxjs/Rx'; 3 | import { InterceptorOptions } from "./interceptor-options"; 4 | import { Interceptor } from "./interceptor"; 5 | export declare class InterceptorService extends Http { 6 | private interceptors; 7 | constructor(backend: ConnectionBackend, defaultOptions: RequestOptions); 8 | /** 9 | Before interceptor 10 | patata 11 | */ 12 | addInterceptor(interceptor: Interceptor): void; 13 | /** Parent overrides **/ 14 | private httpRequest(request); 15 | request(url: string | Request, options?: InterceptorOptions): Observable; 16 | /** 17 | * Performs a request with `get` http method. 18 | */ 19 | get(url: string, options?: InterceptorOptions): Observable; 20 | /** 21 | * Performs a request with `post` http method. 22 | */ 23 | post(url: string, body: any, options?: InterceptorOptions): Observable; 24 | /** 25 | * Performs a request with `put` http method. 26 | */ 27 | put(url: string, body: any, options?: InterceptorOptions): Observable; 28 | /** 29 | * Performs a request with `delete` http method. 30 | */ 31 | delete(url: string, options?: InterceptorOptions): Observable; 32 | /** 33 | * Performs a request with `patch` http method. 34 | */ 35 | patch(url: string, body: any, options?: InterceptorOptions): Observable; 36 | /** 37 | * Performs a request with `head` http method. 38 | */ 39 | head(url: string, options?: InterceptorOptions): Observable; 40 | /** 41 | * Performs a request with `options` http method. 42 | */ 43 | options(url: string, options?: InterceptorOptions): Observable; 44 | /** Private functions **/ 45 | private runBeforeInterceptors(params); 46 | private runAfterInterceptors(response, startOn); 47 | } 48 | -------------------------------------------------------------------------------- /lib/interceptor-service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || function (d, b) { 3 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 4 | function __() { this.constructor = d; } 5 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 6 | }; 7 | var http_1 = require("@angular/http"); 8 | var Rx_1 = require("rxjs/Rx"); 9 | var InterceptorService = (function (_super) { 10 | __extends(InterceptorService, _super); 11 | function InterceptorService(backend, defaultOptions) { 12 | var _this = _super.call(this, backend, defaultOptions) || this; 13 | _this.interceptors = []; 14 | return _this; 15 | } 16 | /** 17 | Before interceptor 18 | patata 19 | */ 20 | InterceptorService.prototype.addInterceptor = function (interceptor) { 21 | this.interceptors.push(interceptor); 22 | }; 23 | /** Parent overrides **/ 24 | InterceptorService.prototype.httpRequest = function (request) { 25 | var _this = this; 26 | request.options = request.options || {}; 27 | request.options.headers = request.options.headers || new http_1.Headers(); 28 | return this.runBeforeInterceptors(request) 29 | .flatMap(function (value, index) { 30 | // We return an observable that merges the result of the request plus the interceptorOptions we need 31 | return Rx_1.Observable.zip(_super.prototype.request.call(_this, value.url, value.options), Rx_1.Observable.of(value.interceptorOptions), function (response, options) { 32 | return { 33 | response: response, 34 | interceptorOptions: options 35 | }; 36 | }).catch(function (err) { 37 | return Rx_1.Observable.of({ 38 | response: err, 39 | interceptorOptions: value.interceptorOptions || {} 40 | }); 41 | }); 42 | }) 43 | .catch(function (err) { 44 | // If it's a cancel, create a fake response and pass it to next interceptors 45 | if (err.error == "cancelled") { 46 | var response = new http_1.ResponseOptions({ 47 | body: null, 48 | status: 0, 49 | statusText: "intercepted", 50 | headers: new http_1.Headers() 51 | }); 52 | return Rx_1.Observable.of({ 53 | response: new http_1.Response(response), 54 | intercepted: true, 55 | interceptorStep: err.position, 56 | interceptorOptions: err.interceptorOptions 57 | }); 58 | } 59 | else { 60 | } 61 | }) 62 | .flatMap(function (value, index) { 63 | var startOn = (value.intercepted) ? value.interceptorStep : _this.interceptors.length - 1; 64 | return _this.runAfterInterceptors(value, startOn); 65 | }) 66 | .flatMap(function (value, index) { 67 | return Rx_1.Observable.of(value.response); 68 | }) 69 | .flatMap(function (value, index) { 70 | if (!value.ok) 71 | return Rx_1.Observable.throw(value); 72 | return Rx_1.Observable.of(value); 73 | }); 74 | }; 75 | InterceptorService.prototype.request = function (url, options) { 76 | options = options || {}; 77 | var responseObservable; 78 | if (typeof url === 'string') { 79 | responseObservable = this.httpRequest({ 80 | url: url, 81 | options: options, 82 | interceptorOptions: options.interceptorOptions || {} 83 | }); 84 | } 85 | else if (url instanceof http_1.Request) { 86 | var request = url; 87 | responseObservable = this.httpRequest({ 88 | url: request.url, 89 | options: { 90 | method: request.method, 91 | headers: request.headers, 92 | url: request.url, 93 | withCredentials: request.withCredentials, 94 | responseType: request.responseType, 95 | body: request.getBody() 96 | }, 97 | interceptorOptions: options.interceptorOptions || {} 98 | }); 99 | } 100 | else { 101 | throw new Error('First argument must be a url string or Request instance.'); 102 | } 103 | return responseObservable; 104 | }; 105 | /** 106 | * Performs a request with `get` http method. 107 | */ 108 | InterceptorService.prototype.get = function (url, options) { 109 | options = options || {}; 110 | options.method = options.method || http_1.RequestMethod.Get; 111 | options.url = options.url || url; 112 | return this.request(url, options); 113 | }; 114 | /** 115 | * Performs a request with `post` http method. 116 | */ 117 | InterceptorService.prototype.post = function (url, body, options) { 118 | options = options || {}; 119 | options.method = options.method || http_1.RequestMethod.Post; 120 | options.url = options.url || url; 121 | options.body = options.body || body; 122 | return this.request(url, options); 123 | }; 124 | /** 125 | * Performs a request with `put` http method. 126 | */ 127 | InterceptorService.prototype.put = function (url, body, options) { 128 | options = options || {}; 129 | options.method = options.method || http_1.RequestMethod.Put; 130 | options.url = options.url || url; 131 | options.body = options.body || body; 132 | return this.request(url, options); 133 | }; 134 | /** 135 | * Performs a request with `delete` http method. 136 | */ 137 | InterceptorService.prototype.delete = function (url, options) { 138 | options = options || {}; 139 | options.method = options.method || http_1.RequestMethod.Delete; 140 | options.url = options.url || url; 141 | return this.request(url, options); 142 | }; 143 | /** 144 | * Performs a request with `patch` http method. 145 | */ 146 | InterceptorService.prototype.patch = function (url, body, options) { 147 | options = options || {}; 148 | options.method = options.method || http_1.RequestMethod.Patch; 149 | options.url = options.url || url; 150 | options.body = options.body || body; 151 | return this.request(url, options); 152 | }; 153 | /** 154 | * Performs a request with `head` http method. 155 | */ 156 | InterceptorService.prototype.head = function (url, options) { 157 | options = options || {}; 158 | options.method = options.method || http_1.RequestMethod.Head; 159 | options.url = options.url || url; 160 | return this.request(url, options); 161 | }; 162 | /** 163 | * Performs a request with `options` http method. 164 | */ 165 | InterceptorService.prototype.options = function (url, options) { 166 | options = options || {}; 167 | options.method = options.method || http_1.RequestMethod.Options; 168 | options.url = options.url || url; 169 | return this.request(url, options); 170 | }; 171 | /** Private functions **/ 172 | InterceptorService.prototype.runBeforeInterceptors = function (params) { 173 | var ret = Rx_1.Observable.of(params); 174 | var _loop_1 = function (i) { 175 | var bf = this_1.interceptors[i]; 176 | if (!bf.interceptBefore) 177 | return "continue"; 178 | ret = ret.flatMap(function (value, index) { 179 | var newObs; 180 | var res = null; 181 | try { 182 | res = bf.interceptBefore(value); 183 | } 184 | catch (ex) { 185 | console.error(ex); 186 | } 187 | if (!res) 188 | newObs = Rx_1.Observable.of(value); 189 | else if (!(res instanceof Rx_1.Observable)) 190 | newObs = Rx_1.Observable.of(res); 191 | else 192 | newObs = res; 193 | return newObs.catch(function (err, caught) { 194 | if (err == "cancelled") { 195 | return Rx_1.Observable.throw({ 196 | error: "cancelled", 197 | interceptorOptions: params.interceptorOptions, 198 | position: i 199 | }); 200 | } 201 | return Rx_1.Observable.throw({ 202 | error: "unknown", 203 | interceptorOptions: params.interceptorOptions, 204 | err: err 205 | }); 206 | }); 207 | }); 208 | }; 209 | var this_1 = this; 210 | for (var i = 0; i < this.interceptors.length; i++) { 211 | _loop_1(i); 212 | } 213 | return ret; 214 | }; 215 | InterceptorService.prototype.runAfterInterceptors = function (response, startOn) { 216 | var ret = Rx_1.Observable.of(response); 217 | var _loop_2 = function (i) { 218 | var af = this_2.interceptors[i]; 219 | if (!af.interceptAfter) 220 | return "continue"; 221 | ret = ret.flatMap(function (value, index) { 222 | var newObs; 223 | var res = null; 224 | try { 225 | res = af.interceptAfter(value); 226 | } 227 | catch (ex) { 228 | console.error(ex); 229 | } 230 | if (!res) 231 | newObs = Rx_1.Observable.of(value); 232 | else if (!(res instanceof Rx_1.Observable)) 233 | newObs = Rx_1.Observable.of(res); 234 | else 235 | newObs = res; 236 | return newObs; 237 | }); 238 | }; 239 | var this_2 = this; 240 | for (var i = startOn; i >= 0; i--) { 241 | _loop_2(i); 242 | } 243 | return ret; 244 | }; 245 | return InterceptorService; 246 | }(http_1.Http)); 247 | exports.InterceptorService = InterceptorService; 248 | //# sourceMappingURL=interceptor-service.js.map -------------------------------------------------------------------------------- /lib/interceptor-service.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"interceptor-service.js","sourceRoot":"","sources":["../src/interceptor-service.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/interceptor.d.ts: -------------------------------------------------------------------------------- 1 | import { InterceptedRequest } from "./intercepted-request"; 2 | import { InterceptedResponse } from "./intercepted-response"; 3 | import { Observable } from 'rxjs/Rx'; 4 | export interface Interceptor { 5 | interceptBefore?(request: InterceptedRequest): Observable | InterceptedRequest; 6 | interceptAfter?(response: InterceptedResponse): Observable | InterceptedResponse; 7 | } 8 | -------------------------------------------------------------------------------- /lib/interceptor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //# sourceMappingURL=interceptor.js.map -------------------------------------------------------------------------------- /lib/interceptor.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"interceptor.js","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-interceptors", 3 | "version": "1.2.4", 4 | "description": "Angular2 interceptor service implementation", 5 | "keywords": [ 6 | "Angular 2", 7 | "Interceptor" 8 | ], 9 | "author": { 10 | "name": "Víctor Oliva", 11 | "email": "olivarra1@gmail.com" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/voliva/angular2-interceptors" 16 | }, 17 | "main": "index.js", 18 | "license": "ISC", 19 | "scripts": { 20 | "build": "rimraf lib && tsc -p src" 21 | }, 22 | "peerDependencies": { 23 | "@angular/core": "^2.0.0", 24 | "@angular/http": "^2.0.0", 25 | "rxjs": "5.0.0-beta.12" 26 | }, 27 | "devDependencies": { 28 | "@angular/common": "^2.0.0", 29 | "@angular/core": "^2.0.0", 30 | "@angular/http": "^2.0.0", 31 | "@angular/platform-browser": "^2.0.0", 32 | "rxjs": "^5.0.0-beta.12", 33 | "typescript": "^2.0.3", 34 | "zone.js": "^0.6.21" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/intercepted-request.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptionsArgs } from '@angular/http'; 2 | 3 | export interface InterceptedRequest { 4 | url: string, 5 | options?: RequestOptionsArgs, 6 | interceptorOptions?: any 7 | } 8 | -------------------------------------------------------------------------------- /src/intercepted-response.ts: -------------------------------------------------------------------------------- 1 | import { Response } from '@angular/http'; 2 | 3 | export interface InterceptedResponse { 4 | response: Response, 5 | intercepted?: Boolean, 6 | interceptorStep?: number, 7 | interceptorOptions?: any 8 | } 9 | -------------------------------------------------------------------------------- /src/interceptor-options.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptionsArgs } from '@angular/http'; 2 | 3 | export interface InterceptorOptions extends RequestOptionsArgs { 4 | interceptorOptions?: any 5 | } 6 | -------------------------------------------------------------------------------- /src/interceptor-provider.ts: -------------------------------------------------------------------------------- 1 | import { FactoryProvider } from '@angular/core'; 2 | import { XHRBackend, RequestOptions } from '@angular/http'; 3 | import { InterceptorService } from './interceptor-service'; 4 | 5 | export function provideInterceptorService(interceptors:any[]):FactoryProvider { 6 | let deps:any[] = [ 7 | XHRBackend, 8 | RequestOptions 9 | ]; 10 | 11 | interceptors = interceptors.map((interceptor:any) => { 12 | if(typeof interceptor == "function"){ 13 | deps.push(interceptor); 14 | return { 15 | useValue: false, 16 | index: deps.length-1 17 | } 18 | }else{ 19 | return { 20 | useValue: interceptor 21 | } 22 | } 23 | }); 24 | 25 | return { 26 | provide: InterceptorService, 27 | useFactory: function(){ 28 | let injectedServices = arguments; 29 | let xhrBackend:XHRBackend = injectedServices[0]; 30 | let requestOptions:RequestOptions = injectedServices[1]; 31 | 32 | let service = new InterceptorService(xhrBackend, requestOptions); 33 | interceptors.forEach((interceptor) => { 34 | if(interceptor.useValue){ 35 | service.addInterceptor(interceptor.useValue); 36 | }else{ 37 | let value = injectedServices[interceptor.index]; 38 | service.addInterceptor(value); 39 | } 40 | }); 41 | return service; 42 | }, 43 | deps: deps, 44 | multi: false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/interceptor-service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConnectionBackend, 3 | Headers, 4 | Http, 5 | Request, 6 | Response, 7 | ResponseOptions, 8 | RequestMethod, 9 | RequestOptions 10 | } from '@angular/http'; 11 | import { Observable, Observer } from 'rxjs/Rx'; 12 | import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; 13 | import { InterceptedRequest } from "./intercepted-request"; 14 | import { InterceptedResponse } from "./intercepted-response"; 15 | import { InterceptorOptions } from "./interceptor-options"; 16 | import { Interceptor } from "./interceptor"; 17 | 18 | export class InterceptorService extends Http { 19 | private interceptors: Array; 20 | 21 | constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) { 22 | super(backend, defaultOptions); 23 | this.interceptors = []; 24 | } 25 | 26 | /** 27 | Before interceptor 28 | patata 29 | */ 30 | addInterceptor(interceptor: Interceptor) { 31 | this.interceptors.push(interceptor); 32 | } 33 | 34 | /** Parent overrides **/ 35 | private httpRequest(request:InterceptedRequest): Observable { 36 | request.options = this.getOptions(request.options); 37 | request.options.headers = request.options.headers || new Headers(); 38 | return this.runBeforeInterceptors(request) 39 | .flatMap((value: InterceptedRequest, index: number) => { 40 | // We return an observable that merges the result of the request plus the interceptorOptions we need 41 | return Observable.zip( 42 | super.request(value.url, value.options), 43 | Observable.of(value.interceptorOptions), 44 | function(response, options) { 45 | return { 46 | response: response, 47 | interceptorOptions: options 48 | } as InterceptedResponse; 49 | } 50 | ).catch((err: any) => { 51 | return Observable.of({ 52 | response: err, 53 | interceptorOptions: value.interceptorOptions || {} 54 | } as InterceptedResponse); 55 | }); 56 | }) 57 | .catch((err: any) => { 58 | // If it's a cancel, create a fake response and pass it to next interceptors 59 | if (err.error == "cancelled") { 60 | var response = new ResponseOptions({ 61 | body: null, 62 | status: 0, 63 | statusText: "intercepted", 64 | headers: new Headers() 65 | }) 66 | return Observable.of({ 67 | response: new Response(response), 68 | intercepted: true, 69 | interceptorStep: err.position, 70 | interceptorOptions: err.interceptorOptions 71 | }); 72 | } else { 73 | // We had an exception in the pipeline... woops? TODO 74 | } 75 | }) 76 | .flatMap((value: InterceptedResponse, index: number) => { 77 | var startOn = (value.intercepted) ? value.interceptorStep : this.interceptors.length - 1; 78 | return this.runAfterInterceptors(value, startOn); 79 | }) 80 | .flatMap((value: InterceptedResponse, index: number) => { 81 | return Observable.of(value.response); 82 | }) 83 | .flatMap((value: Response, index: number) => { 84 | if (!value.ok) 85 | return Observable.throw(value); 86 | 87 | return Observable.of(value); 88 | }); 89 | } 90 | 91 | request(url: string|Request, options?: InterceptorOptions): Observable { 92 | options = options || {}; 93 | let responseObservable: any; 94 | if (typeof url === 'string') { 95 | responseObservable = this.httpRequest({ 96 | url: url, 97 | options: options, 98 | interceptorOptions: options.interceptorOptions || {} 99 | }); 100 | } else if (url instanceof Request) { 101 | let request:Request = url; 102 | responseObservable = this.httpRequest({ 103 | url: request.url, 104 | options: { 105 | method: request.method, 106 | headers: request.headers, 107 | url: request.url, 108 | withCredentials: request.withCredentials, 109 | responseType: request.responseType, 110 | body: request.getBody() 111 | }, 112 | interceptorOptions: options.interceptorOptions || {} 113 | }); 114 | } else { 115 | throw new Error('First argument must be a url string or Request instance.'); 116 | } 117 | return responseObservable; 118 | } 119 | 120 | getOptions(options ?: InterceptorOptions): InterceptorOptions { 121 | if (options) { 122 | // Shallow copy to avoid modifying method/url on incoming options 123 | return {...options}; 124 | } 125 | return {}; 126 | } 127 | 128 | /** 129 | * Performs a request with `get` http method. 130 | */ 131 | get(url: string, options?: InterceptorOptions): Observable { 132 | options = this.getOptions(options); 133 | options.method = options.method || RequestMethod.Get; 134 | options.url = options.url || url; 135 | return this.request(url, options); 136 | } 137 | 138 | /** 139 | * Performs a request with `post` http method. 140 | */ 141 | post(url: string, body: any, options?: InterceptorOptions): Observable { 142 | options = this.getOptions(options); 143 | options.method = options.method || RequestMethod.Post; 144 | options.url = options.url || url; 145 | options.body = options.body || body; 146 | return this.request(url, options); 147 | } 148 | 149 | /** 150 | * Performs a request with `put` http method. 151 | */ 152 | put(url: string, body: any, options?: InterceptorOptions): Observable { 153 | options = this.getOptions(options); 154 | options.method = options.method || RequestMethod.Put; 155 | options.url = options.url || url; 156 | options.body = options.body || body; 157 | return this.request(url, options); 158 | } 159 | 160 | /** 161 | * Performs a request with `delete` http method. 162 | */ 163 | delete(url: string, options?: InterceptorOptions): Observable { 164 | options = this.getOptions(options); 165 | options.method = options.method || RequestMethod.Delete; 166 | options.url = options.url || url; 167 | return this.request(url, options); 168 | } 169 | 170 | /** 171 | * Performs a request with `patch` http method. 172 | */ 173 | patch(url: string, body: any, options?: InterceptorOptions): Observable { 174 | options = this.getOptions(options); 175 | options.method = options.method || RequestMethod.Patch; 176 | options.url = options.url || url; 177 | options.body = options.body || body; 178 | return this.request(url, options); 179 | } 180 | 181 | /** 182 | * Performs a request with `head` http method. 183 | */ 184 | head(url: string, options?: InterceptorOptions): Observable { 185 | options = this.getOptions(options); 186 | options.method = options.method || RequestMethod.Head; 187 | options.url = options.url || url; 188 | return this.request(url, options); 189 | } 190 | 191 | /** 192 | * Performs a request with `options` http method. 193 | */ 194 | options(url: string, options?: InterceptorOptions): Observable { 195 | options = this.getOptions(options); 196 | options.method = options.method || RequestMethod.Options; 197 | options.url = options.url || url; 198 | return this.request(url, options); 199 | } 200 | 201 | /** Private functions **/ 202 | private runBeforeInterceptors(params: InterceptedRequest): Observable { 203 | let ret: Observable = Observable.of(params); 204 | 205 | for (let i = 0; i < this.interceptors.length; i++) { 206 | let bf: Interceptor = this.interceptors[i]; 207 | if (!bf.interceptBefore) continue; 208 | 209 | ret = ret.flatMap((value: InterceptedRequest, index: number) => { 210 | let newObs: Observable; 211 | let res = null; 212 | try { 213 | res = bf.interceptBefore(value); 214 | } catch (ex) { 215 | console.error(ex); 216 | } 217 | if (!res) newObs = Observable.of(value); 218 | else if (!(res instanceof Observable)) newObs = Observable.of(res); 219 | else newObs = res; 220 | 221 | return newObs.catch((err: any, caught: Observable) => { 222 | if (err == "cancelled") { 223 | return >Observable.throw({ 224 | error: "cancelled", 225 | interceptorOptions: params.interceptorOptions, 226 | position: i 227 | }); 228 | } 229 | return >Observable.throw({ 230 | error: "unknown", 231 | interceptorOptions: params.interceptorOptions, 232 | err: err 233 | }); 234 | }); 235 | }); 236 | } 237 | 238 | return ret; 239 | } 240 | 241 | private runAfterInterceptors(response: InterceptedResponse, startOn: number): Observable { 242 | let ret: Observable = Observable.of(response); 243 | 244 | for (let i = startOn; i >= 0; i--) { 245 | let af: Interceptor = this.interceptors[i]; 246 | if (!af.interceptAfter) continue; 247 | 248 | ret = ret.flatMap((value: InterceptedResponse, index) => { 249 | let newObs: Observable; 250 | 251 | let res = null; 252 | try { 253 | res = af.interceptAfter(value); 254 | } catch (ex) { 255 | console.error(ex); 256 | } 257 | if (!res) newObs = Observable.of(value); 258 | else if (!(res instanceof Observable)) newObs = Observable.of(res); 259 | else newObs = res; 260 | 261 | return newObs; 262 | }); 263 | } 264 | return ret; 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/interceptor.ts: -------------------------------------------------------------------------------- 1 | import { InterceptedRequest } from "./intercepted-request"; 2 | import { InterceptedResponse } from "./intercepted-response"; 3 | import { Observable } from 'rxjs/Rx'; 4 | 5 | export interface Interceptor { 6 | interceptBefore?(request: InterceptedRequest): Observable | InterceptedRequest 7 | interceptAfter?(response: InterceptedResponse): Observable | InterceptedResponse 8 | } 9 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false, 11 | "outDir": "../lib", 12 | "declaration": true 13 | }, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@angular/common@^2.0.0": 6 | version "2.3.0" 7 | resolved "https://registry.yarnpkg.com/@angular/common/-/common-2.3.0.tgz#16b0034fe43ae70875343f23e19835435edd118e" 8 | 9 | "@angular/core@^2.0.0": 10 | version "2.3.0" 11 | resolved "https://registry.yarnpkg.com/@angular/core/-/core-2.3.0.tgz#e60bd398584d69467d075d001b718364174a2534" 12 | 13 | "@angular/http@^2.0.0": 14 | version "2.3.0" 15 | resolved "https://registry.yarnpkg.com/@angular/http/-/http-2.3.0.tgz#0c0823d69723d96d294e58881397fec1ed803f73" 16 | 17 | "@angular/platform-browser@^2.0.0": 18 | version "2.3.0" 19 | resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-2.3.0.tgz#93259309cfb4e8fdb39ececa0b205f4caf002e6c" 20 | 21 | rxjs@^5.0.0-beta.12: 22 | version "5.0.1" 23 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.0.1.tgz#3a69bdf9f0ca0a986303370d4708f72bdfac8356" 24 | dependencies: 25 | symbol-observable "^1.0.1" 26 | 27 | symbol-observable@^1.0.1: 28 | version "1.0.4" 29 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" 30 | 31 | typescript@^2.0.3: 32 | version "2.1.4" 33 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.4.tgz#b53b69fb841126acb1dd4b397d21daba87572251" 34 | 35 | zone.js@^0.6.21: 36 | version "0.6.26" 37 | resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.6.26.tgz#067c13b8b80223a89b62e9dc82680f09762c4636" 38 | --------------------------------------------------------------------------------