I'm using an HTTP interceptor in order to add auth token to requests but when the http client fires the request, this is intercepted and sent twice
This is my HttpClient call
searchProd(query: string, limit?: number): Observable<Product[]> {
let _limit = limit || 5;
return this.http.get<Product[]>(`${API_CONST.HOST}/${API_CONST.PRODUCT}?search=${query}&limit=${_limit}`);
}
This is my app.module.ts
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { TokenInterceptor } from './auth/token.interceptor';
....
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
ApiService,
AuthGuardService,
SettingsService,
{
provide : HTTP_INTERCEPTORS,
useClass : TokenInterceptor,
multi : true
}
],
entryComponents: [ ... ],
bootstrap: [ ... ]
})
This is my token.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from '@angular/common/http';
import { AngularFireAuth } from '@angular/fire/auth';
import { Observable } from 'rxjs';
import { AuthGuardService } from './auth-guard.service';
import { API_CONST } from '../services/api/api.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private no_auth_endpoints = [
`${API_CONST.HOST}/${API_CONST.PRODUCT}`
]
private token = null;
constructor(public af: AngularFireAuth, private authGuard: AuthGuardService) {
this.token = authGuard.getToken();
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const headersConfig = {
'Authorization': `Bearer ${this.token}`
};
let isAuthEnpoint = true;
this.no_auth_endpoints.forEach(endpoint => {
if(request.url.includes(endpoint))
isAuthEnpoint = false;
})
if (!request.headers.has('Authorization') && isAuthEnpoint) {
const modified = request.clone({
setHeaders : headersConfig
});
return next.handle(modified); //this line is executed twice!
}
else {
return next.handle(request); //this line is executed twice!
}
}
}
Throught the chrome dev tools i see the same request sent twice in the network tab. During debugging I saw the http request send by searchProd once but when it's intecepted the next.handle() is executed twice. How to fix that in order to send only one request?
EDIT: This is what is shown in network tab
EDIT2: This is the code where I call the searchProd(string) function.
component.html
<mat-form-field class="bottom-search-field">
<input [formControl]="autoCompleteControl" type="text" placeholder="Aggiungi un prodotto"
matInput [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="onSelectionChanged($event)">
<mat-option *ngFor="let item of searchResults | async; let index = index" [value]="item.description | titlecase">
{{ item.description | titlecase}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
component.ts
public autoCompleteControl = new FormControl();
...
ngOnInit(): void {
this.searchResults = this.autoCompleteControl.valueChanges.pipe(
startWith(''),
switchMap(value => {
if (value.length > 3) {
let prodSearched = this.apiService.searchProd(value);
prodSearched.pipe(share()); // ADDED PIPE SHARE
this.saveProdSearched(prodSearched);
return prodSearched;
} else {
return of(null);
}
})
);
}
//This function save the last result inside of an array of Product
private saveProdSearched(prodSearched: Observable<Product[]>) {
prodSearched.subscribe(items => {
this.lastSearch = items
})
}
searchProd
? – Kennieasync
pipe onsearchResults
in two different places in your template. Try adding theshareReplay(1)
operator call into your stream pipeline. – KenniesearchResults
– KenniesearchResults | async
to some variable anywhere else in the template? Are you manually subscribingsearchResults
in your component? DidshareReplay(1)
had any effect? The interceptor code is fine, your stream pipe is fine. ThevalueChanges
stream is correctly emitting single values. If it wasnt the case, all requests other than the last would be canceled because of theswitchMap
. So I agree with @JBNizet – KenniedistinctUntilChanged
operator, at least to see if the valueChanges doesn't emit the same value twice – Antimonicthis.saveProdSearched(prodSearched)
inside the component.ts block. Because I subscribe to the prodSearched observable and so I fire another request but I don't know why. I have to mantain this behaviour in order to save the results for other purposes. How can I obtain the same without subscribing/launching the request again? I tried withprodSearched.pipe(share())
before passing it to the function but nothing changed. I provide the code inside the edit2. – TreatiseshareReplay(1)
at the end of yourpipe
call – Kennie