Skip to content

Commit 2346418

Browse files
committed
fix(api): Testing issue with Observable.create
1 parent 926be41 commit 2346418

File tree

3 files changed

+96
-58
lines changed

3 files changed

+96
-58
lines changed

README.md

Lines changed: 81 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ npm install x-ng4-http-interceptor-dontuse --save
1919
And it should be importable with webpack out of the box
2020

2121
# Usage
22+
2223
## Set up InterceptorService
24+
2325
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:
2426

2527
```ts
@@ -53,7 +55,9 @@ export function interceptorFactory(xhrBackend: XHRBackend, requestOptions: Reque
5355
```
5456

5557
## Using InterceptorService
58+
5659
Once we have it set up, we can use it in our Controllers as if we were using the default Angular `Http` service:
60+
5761
```ts
5862
import { Component } from '@angular/core';
5963
import { InterceptorService } from 'x-ng4-http-interceptor-dontuse';
@@ -64,21 +68,22 @@ import { InterceptorService } from 'x-ng4-http-interceptor-dontuse';
6468
moduleId: 'my-module'
6569
})
6670
export class MyComponent {
67-
68-
constructor(
69-
private http: InterceptorService) {
70-
}
71-
72-
ngOnInit(){
73-
this.http.get("http://www.example.com/").subscribe(
74-
(res) => console.log(res),
75-
(err) => console.error(err),
76-
() => console.log("Yay"));
71+
constructor(private http: InterceptorService) {}
72+
73+
ngOnInit() {
74+
this.http
75+
.get('http://www.example.com/')
76+
.subscribe(
77+
res => console.log(res),
78+
err => console.error(err),
79+
() => console.log('Yay')
80+
);
7781
}
7882
}
7983
```
8084

8185
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`:
86+
8287
```ts
8388
{
8489
provide: Http,
@@ -88,13 +93,14 @@ We can also "cheat" the Injector so that every time we ask for the `Http` we get
8893
```
8994

9095
## Creating your own Interceptor
96+
9197
Basically, an interceptor has the option to selectively implement one more of the following methods depending on what part of the flow it wants to intercept. i.e modify flow/take action.
9298

9399
Here is the interceptor interface that details which method is invoked in what part of the flow
94100

95101
```ts
96102
import { Request, RequestOptionsArgs } from '@angular/http';
97-
import { Observable } from 'rxjs/Rx';
103+
import { Observable } from 'rxjs/Observable';
98104

99105
import { InterceptorRequest } from './interceptor-request';
100106
import { InterceptorRequestOptionsArgs } from './interceptor-request-options-args';
@@ -117,14 +123,16 @@ import { InterceptorResponseWrapper } from './interceptor-response-wrapper';
117123
* as request private storage
118124
*/
119125
export interface Interceptor {
120-
121126
/**
122127
* Invoked once for each of the interceptors in the chain; in the order defined in the chain,\
123128
* unless any of the earlier interceptors asked to complete the flow/return response/throw error to subscriber
124129
*
125130
* Gives the ability to transform the request
126131
*/
127-
beforeRequest?(request: InterceptorRequest, interceptorStep: number): Observable<InterceptorRequest> | InterceptorRequest | void;
132+
beforeRequest?(
133+
request: InterceptorRequest,
134+
interceptorStep: number
135+
): Observable<InterceptorRequest> | InterceptorRequest | void;
128136

129137
/**
130138
* Invoked once for each of the interceptors in the chain; in the reverse order of chain,\
@@ -137,8 +145,10 @@ export interface Interceptor {
137145
* You can know if the respons is generated by short circuit handler/err handler,\
138146
* by looking at the `responseGeneratedByShortCircuitHandler` & `responseGeneratedByErrHandler` flags
139147
*/
140-
onResponse?(response: InterceptorResponseWrapper,
141-
interceptorStep: number): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
148+
onResponse?(
149+
response: InterceptorResponseWrapper,
150+
interceptorStep: number
151+
): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
142152

143153
/**
144154
* Invoked once for each of the interceptors in the chain; in the reverse order of chain,\
@@ -148,8 +158,10 @@ export interface Interceptor {
148158
* If no `onShortCircuit(..)` handlers before this handler returns any response/force request to complete
149159
* An error will be thrown back to the subscriber
150160
*/
151-
onShortCircuit?(response: InterceptorResponseWrapper,
152-
interceptorStep: number): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
161+
onShortCircuit?(
162+
response: InterceptorResponseWrapper,
163+
interceptorStep: number
164+
): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
153165

154166
/**
155167
* Invoked when the flow encounters any error along the interceptor chain.
@@ -160,52 +172,71 @@ export interface Interceptor {
160172
* If no `onErr(..)` handlers before the first interceptor (last in the response cycle)
161173
* handler returns any response, the error will be thrown back to the subscriber
162174
*/
163-
onErr?(response: InterceptorResponseWrapper,
164-
interceptorStep: number): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
175+
onErr?(
176+
response: InterceptorResponseWrapper,
177+
interceptorStep: number
178+
): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void;
165179

166180
/**
167181
* Invoked when any one in the interceptor chain forces request completion/return response/error
168182
* Use this method to perform operations that should be performed irrespective of what the other interceptors in the chain does
169183
* such as stopping progress bar/logging
170184
*/
171-
onForceCompleteOrForceReturn?(response: InterceptorResponseWrapper,
172-
interceptorStep: number): void;
185+
onForceCompleteOrForceReturn?(
186+
response: InterceptorResponseWrapper,
187+
interceptorStep: number
188+
): void;
173189

174190
/**
175191
* Invoked when the user unsubscribes while the request is still being handled
176192
* Use this method to perform cleanup operations that should be performed when the request is cancelled by user
177193
* such as stopping progress bar
178194
*/
179-
onUnsubscribe?(interceptorStep: number, url: string | Request, options?: RequestOptionsArgs | InterceptorRequestOptionsArgs): void;
180-
195+
onUnsubscribe?(
196+
interceptorStep: number,
197+
url: string | Request,
198+
options?: RequestOptionsArgs | InterceptorRequestOptionsArgs
199+
): void;
181200
}
182201
```
183202

184203
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:
185204

186205
```ts
187-
import { Interceptor, InterceptorRequest, InterceptorResponseWrapper } from 'x-ng4-http-interceptor-dontuse';
206+
import {
207+
Interceptor,
208+
InterceptorRequest,
209+
InterceptorResponseWrapper
210+
} from 'x-ng4-http-interceptor-dontuse';
188211

189212
export class ServerURLInterceptor implements Interceptor {
190-
beforeRequest(request: InterceptorRequest): Observable<InterceptorRequest> | InterceptorRequest | void {
191-
// Do whatever with request, such as chaing request by adding additional headers such as `Content-Type` (or) `Authorization`
192-
// refer to jsdoc of each of 'InterceptorRequest' to know the significance of return values & additional features such as short circuiting the whole flow
193-
let modifiedOptions: RequestOptionsArgs = addHeaders(request.options);
194-
return InterceptorRequestBuilder.from(request)
195-
.options(modifiedOptions)
196-
.build();
197-
}
198-
199-
onResponse(responseWrapper: InterceptorResponseWrapper, interceptorStep?: number): Observable<InterceptorResponseWrapper> | InterceptorResponseWrapper | void {
200-
// Do whatever with responseWrapper: get/edit response
201-
// refer to jsdoc of each of 'InterceptorResponseWrapper' to know the significance of return values & additional features such as short circuiting the whole flow
213+
beforeRequest(
214+
request: InterceptorRequest
215+
): Observable<InterceptorRequest> | InterceptorRequest | void {
216+
// Do whatever with request, such as chaing request by adding additional headers such as `Content-Type` (or) `Authorization`
217+
// refer to jsdoc of each of 'InterceptorRequest' to know the significance of return values & additional features such as short circuiting the whole flow
218+
let modifiedOptions: RequestOptionsArgs = addHeaders(request.options);
219+
return InterceptorRequestBuilder.from(request)
220+
.options(modifiedOptions)
221+
.build();
222+
}
202223

203-
return InterceptorResponseWrapperBuilder.from(responseWrapper)
204-
.forceReturnResponse(true)
205-
.build();
206-
}
224+
onResponse(
225+
responseWrapper: InterceptorResponseWrapper,
226+
interceptorStep?: number
227+
):
228+
| Observable<InterceptorResponseWrapper>
229+
| InterceptorResponseWrapper
230+
| void {
231+
// Do whatever with responseWrapper: get/edit response
232+
// refer to jsdoc of each of 'InterceptorResponseWrapper' to know the significance of return values & additional features such as short circuiting the whole flow
233+
234+
return InterceptorResponseWrapperBuilder.from(responseWrapper)
235+
.forceReturnResponse(true)
236+
.build();
237+
}
207238

208-
// can chose to seletively implement any of the four hooks mentioned in the Interceptor interface
239+
// can chose to seletively implement any of the four hooks mentioned in the Interceptor interface
209240
}
210241
```
211242

@@ -234,23 +265,27 @@ class InterceptedResponseWrapper {
234265
// a lot more properties; refer to jsdoc
235266
}
236267
```
268+
237269
`sharedData` on `InterceptorRequest` is guaranteed to be the same of that one of `InterceptedResponseWrapper` for the same call: The stuff you put in `interceptorOptions` while in `interceptBefore` will be available when you get `onResponse(..)` called.
238270

239271
## Creating one Injectable Interceptor
272+
240273
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.
241274

242275
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.
243276

244277
To do that you have to do some steps in the module/factory declaration file:
245-
1. Create a Service (`@Injectable()` annotation) that implements `Interceptor` and the interceptor methods.
246-
2. Define his provider before `InterceptorService`
247-
3. Add it as a parameter to the factory function
248-
4. Add it to the `deps` array. Note that the order of the elements have to match the one on the factory function.
249-
5. Add it to the pipeline
278+
279+
1. Create a Service (`@Injectable()` annotation) that implements `Interceptor` and the interceptor methods.
280+
2. Define his provider before `InterceptorService`
281+
3. Add it as a parameter to the factory function
282+
4. Add it to the `deps` array. Note that the order of the elements have to match the one on the factory function.
283+
5. Add it to the pipeline
250284

251285
If you are using the `provideInterceptorService` option (without AoT Compiler support), then you can skip steps 2-4.
252286

253287
If our `ServerURLInterceptor` were a Service, we would have a module declaration like:
288+
254289
```ts
255290
import { InterceptorService } from 'x-ng4-http-interceptor-dontuse';
256291
import { ServerURLInterceptor } from './services/serverURLInterceptor';

src/interceptor-response-wrapper.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { InterceptorResponseWrapperBuilder } from './interceptor-response-wrappe
55
import { InterceptorUtils } from './interceptor-utils';
66

77
export class InterceptorResponseWrapper {
8-
98
/**
109
* url which will be cascaded to the final {@code Http} call
1110
*/
@@ -78,6 +77,10 @@ export class InterceptorResponseWrapper {
7877
return this._url;
7978
}
8079

80+
get urlAsStr(): string {
81+
return typeof this._url === 'string' ? this._url : this._url.url;
82+
}
83+
8184
get options(): any {
8285
return this._options;
8386
}
@@ -123,15 +126,20 @@ export class InterceptorResponseWrapper {
123126
}
124127

125128
isShortCircuited(): boolean {
126-
return this._shortCircuitTriggeredBy !== undefined && this._shortCircuitTriggeredBy !== null && !!this._shortCircuitTriggeredBy;
129+
return (
130+
this._shortCircuitTriggeredBy !== undefined &&
131+
this._shortCircuitTriggeredBy !== null &&
132+
!!this._shortCircuitTriggeredBy
133+
);
127134
}
128135

129136
circuitShortedByMe(currentStep: number): boolean {
130-
return this.isShortCircuited() && this._shortCircuitTriggeredBy === currentStep;
137+
return (
138+
this.isShortCircuited() && this._shortCircuitTriggeredBy === currentStep
139+
);
131140
}
132141

133142
errThrownByMe(currentStep: number): boolean {
134143
return !!this._errEncounteredAt && this._errEncounteredAt === currentStep;
135144
}
136-
137145
}

src/interceptor-service.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,15 @@ export class InterceptorService extends Http {
9090
(e: Error) => observer.error(e),
9191
() => observer.complete()
9292
);
93-
observer.add(() => {
93+
return function() {
9494
subscription.unsubscribe();
9595
for (let index = this.interceptors.length - 1; index >= 0; index--) {
9696
const interceptor = this.interceptors[index];
9797
if (interceptor.onUnsubscribe !== undefined) {
9898
interceptor.onUnsubscribe(index, url, options, reqNum);
9999
}
100100
}
101-
});
102-
return this;
101+
};
103102
});
104103
}
105104

@@ -216,10 +215,6 @@ export class InterceptorService extends Http {
216215
this._realResponseObservableTransformer = value;
217216
}
218217

219-
public newHttpNative(): HttpDirect {
220-
return new this.HttpDirect();
221-
}
222-
223218
/** Private functions **/
224219
private httpRequest(
225220
request: InterceptorRequest,
@@ -268,7 +263,7 @@ export class InterceptorService extends Http {
268263
response$ = this._realResponseObservableTransformer.transform(
269264
response$,
270265
transformedRequest,
271-
this.newHttpNative(),
266+
new this.HttpDirect(),
272267
this
273268
);
274269
}

0 commit comments

Comments
 (0)