Upon observation, it has been noted that there is a duplicate triggering of the request when intercepting HTTP response and using subscribe to retrieve the value in the Observable response.
Below is the code snippet:
Intercepting Http Request and Response by extending it (http.service.ts)
import { Injectable } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers, ConnectionBackend } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { LoggedInUserApi } from './loggedInUser.service';
@Injectable()
export class HttpService extends Http {
constructor(private loggedInUserApi: LoggedInUserApi, backend: XHRBackend, options: RequestOptions) {
super(backend, options);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.request(url, options));
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.get(url, options));
}
post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.post(url, body, options));
}
put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.put(url, body, options));
}
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.delete(url, options));
}
handleResponseHeader(header) {
console.log(header);
}
intercept(observableResponse: Observable<Response>): Observable<Response> {
observableResponse.subscribe(response => this.handleResponseHeader(response.headers));
return observableResponse;
}
}
The issue seems to arise from subscribing to the observable response. If .map is used instead of .subscribe, the issue does not occur, but the desired result - like returning header values from the response - is not achieved.
In app.module.ts, we specify the use of HttpService instead of Http (app.module.ts)
.....
providers: [
......
{
provide: Http,
useFactory: (loggedInUserApi: service.LoggedInUserApi, xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
new service.HttpService(loggedInUserApi, xhrBackend, requestOptions),
deps: [service.LoggedInUserApi, XHRBackend, RequestOptions]
}
],
....
Within the service, the server API call to add a user using the post method appears to be called twice causing the issue of duplication. It should ideally trigger only once. (User-operation.service.ts)
public addUser(body: models.User, extraHttpRequestParams?: any): Observable<models.User> {
// verify required parameter 'body' is not null or undefined
if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling addUser.');
}
const path = this.basePath + '/user';
let queryParameters = new URLSearchParams();
let headerParams = new Headers({ 'Content-Type': 'application/json' });
let requestOptions: RequestOptionsArgs = {
method: 'POST',
headers: headerParams,
search: queryParameters
};
requestOptions.body = JSON.stringify(body);
return this.http.request(path, requestOptions)
.map((response: Response) => {
if (response.status === 204) {
return undefined;
} else {
return response.json();
}
}).share();
}
In the user component, the service is invoked upon button click event to pass the user model. (User.component.ts)
addUser(event) {
// To add user using api
this.busy = this.api.addUser(this.user)
.subscribe(
() => {
DialogService.displayStatusMessage({ message: 'User configurations saved successfully.', type: 'success' });
this.router.navigate(['users']);
},
(error: any) => {
throw ({ message: error.json().message });
}
);
}
References to similar issues mention cold and hot observables, suggesting to use .share to make the observable hot and prevent the issue. Attempts were made in this direction but the solution did not yield successful results.