Skip to content

Commit 676ec48

Browse files
authored
Merge pull request #77 from mpalourdio/filtered_headers
Filter HTTP requests by HTTP headers
2 parents 1d6f2ec + 2514751 commit 676ec48

File tree

8 files changed

+193
-60
lines changed

8 files changed

+193
-60
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v2.3.0
4+
5+
This release adds the possibility to filter HTTP requests that should not be handled by the interceptor by providing an array of HTTP headers to the component's ``filteredHeaders`` property.
6+
37
## v2.2.0
48

59
This release adds the possibility to filter HTTP requests that should not be handled by the interceptor by providing an array of HTTP methods to the component's ``filteredMethods`` property.

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,23 @@ You can define your own loader component in place of the built-in ones. The need
127127

128128
You can find some short examples [here](https://gist.github.com/mpalourdio/2c0bec03d610b24ff49db649fbb69a48) and [here](https://gist.github.com/mpalourdio/e05b4495de2abeeecfcf92d70e4ef93e).
129129

130-
## Requests filtering by URL or by HTTP method
130+
## Requests filtering by URL, HTTP method or HTTP headers
131131

132132
You can filter the http requests that shouldn't be caught by the interceptor by providing **an array of regex patterns**:
133133
```xml
134134
<spinner [filteredUrlPatterns]="['\\d', '[a-zA-Z]', 'my-api']"></spinner>
135135
```
136136

137-
You can also filter the http requests by providing **an array of HTTP methods** (case insensitive):
137+
You can filter the http requests by providing **an array of HTTP methods** (case insensitive):
138138
```xml
139139
<spinner [filteredMethods]="['gEt', 'POST', 'PuT']"></spinner>
140140
```
141141

142+
You can also filter the http requests by providing **an array of HTTP headers** (case insensitive):
143+
```xml
144+
<spinner [filteredHeaders]="['hEaDeR', 'AnoTheR-HeAdEr']"></spinner>
145+
```
146+
142147
## Manually show and hide the spinner
143148

144149
You can manually show and hide the spinner component if needed. You must use the ``SpinnerVisibilityService`` for this purpose.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ng-http-loader",
3-
"version": "2.2.0",
3+
"version": "2.3.0",
44
"scripts": {
55
"ng": "ng",
66
"build": "ng build",

src/lib/components/spinner/spinner.component.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export class SpinnerComponent implements OnDestroy, OnInit {
3434
@Input()
3535
public filteredMethods: string[] = [];
3636
@Input()
37+
public filteredHeaders: string[] = [];
38+
@Input()
3739
public debounceDelay = 0;
3840
@Input()
3941
public minDuration = 0;
@@ -68,6 +70,11 @@ export class SpinnerComponent implements OnDestroy, OnInit {
6870
throw new TypeError('`filteredMethods` must be an array.');
6971
}
7072
this.pendingInterceptorService.filteredMethods = this.filteredMethods;
73+
74+
if (!(this.filteredHeaders instanceof Array)) {
75+
throw new TypeError('`filteredHeaders` must be an array.');
76+
}
77+
this.pendingInterceptorService.filteredHeaders = this.filteredHeaders;
7178
}
7279

7380
ngOnDestroy(): void {

src/lib/services/pending-interceptor.service.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class PendingInterceptorService implements HttpInterceptor {
2020
private _pendingRequestsStatus: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
2121
private _filteredUrlPatterns: RegExp[] = [];
2222
private _filteredMethods: string[] = [];
23+
private _filteredHeaders: string[] = [];
2324
private _forceByPass: boolean;
2425

2526
/** @deprecated Deprecated in favor of pendingRequestsStatus$ */
@@ -43,6 +44,10 @@ export class PendingInterceptorService implements HttpInterceptor {
4344
this._filteredMethods = httpMethods;
4445
}
4546

47+
set filteredHeaders(value: string[]) {
48+
this._filteredHeaders = value;
49+
}
50+
4651
set forceByPass(value: boolean) {
4752
this._forceByPass = value;
4853
}
@@ -59,9 +64,16 @@ export class PendingInterceptorService implements HttpInterceptor {
5964
});
6065
}
6166

67+
private shouldBypassHeader(req: HttpRequest<any>): boolean {
68+
return this._filteredHeaders.some(e => {
69+
return req.headers.has(e);
70+
});
71+
}
72+
6273
private shouldBypass(req: HttpRequest<any>): boolean {
6374
return this.shouldBypassUrl(req.urlWithParams)
6475
|| this.shouldBypassMethod(req)
76+
|| this.shouldBypassHeader(req)
6577
|| this._forceByPass;
6678
}
6779

src/test/components/spinner/spinner.component.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,23 @@ describe('SpinnerComponent', () => {
160160
}
161161
)));
162162

163+
it('should not show the spinner if the request is filtered by HTTP header', fakeAsync(inject(
164+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
165+
component.filteredHeaders.push('header-to-filter');
166+
fixture.detectChanges();
167+
168+
http.get('/fake', {
169+
headers: {
170+
'header-to-filter': 'value'
171+
}
172+
}).subscribe();
173+
174+
tick();
175+
expect(component.isSpinnerVisible).toBeFalsy();
176+
httpMock.expectOne('/fake').flush({});
177+
}
178+
)));
179+
163180
it('should take care of query strings in filteredUrlPatterns', fakeAsync(inject(
164181
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
165182
component.filteredUrlPatterns.push('bar');
@@ -219,6 +236,30 @@ describe('SpinnerComponent', () => {
219236
}
220237
)));
221238

239+
it('should correctly filter by HTTP header with several requests', fakeAsync(inject(
240+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
241+
component.filteredHeaders.push('My-HeAdER');
242+
fixture.detectChanges();
243+
244+
http.get('/12345', {
245+
headers: {
246+
'my-header': 'value'
247+
}
248+
}).subscribe();
249+
tick();
250+
expect(component.isSpinnerVisible).toBeFalsy();
251+
httpMock.expectOne('/12345').flush({});
252+
253+
http.get('/fake').subscribe();
254+
tick();
255+
expect(component.isSpinnerVisible).toBeTruthy();
256+
httpMock.expectOne('/fake').flush({});
257+
258+
tick();
259+
expect(component.isSpinnerVisible).toBeFalsy();
260+
}
261+
)));
262+
222263
it('should throw an error if filteredUrlPatterns is not an array', () => {
223264
component.filteredUrlPatterns = null;
224265
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredUrlPatterns` must be an array.'));
@@ -229,6 +270,11 @@ describe('SpinnerComponent', () => {
229270
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredMethods` must be an array.'));
230271
});
231272

273+
it('should throw an error if filteredHeaders is not an array', () => {
274+
component.filteredHeaders = null;
275+
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredHeaders` must be an array.'));
276+
});
277+
232278
it('should show the spinner even if the component is created after the HTTP request is performed', fakeAsync(inject(
233279
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
234280
http.get('/fake').subscribe();

src/test/services/pending-interceptor.service.spec.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,6 @@ describe('PendingInterceptorService', () => {
9696

9797
const testRequest = httpMock.expectOne('/fake');
9898
testRequest.flush({}, {
99-
'headers': {
100-
'name': 'useless-header'
101-
},
10299
'status': 404,
103100
'statusText': statusText
104101
});

0 commit comments

Comments
 (0)