Using Angular 4.3.1 and HttpClient, I need to modify the request and response by async service into the HttpInterceptor of httpClient,
Example for modifying the requ
The answers above seem to be fine. I had same requirements but faced issues due to update in different dependencies and operators. Took me some time but I found one working solution to this specific issue.
If you are using Angular 7 and RxJs version 6+ with requirements for Async Interceptor request then you can use this code which works with latest version of NgRx store and related dependencies:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let combRef = combineLatest(this.store.select(App.getAppName));
return combRef.pipe( take(1), switchMap((result) => {
// Perform any updates in the request here
return next.handle(request).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('event--->>>', event);
}
return event;
}),
catchError((error: HttpErrorResponse) => {
let data = {};
data = {
reason: error && error.error.reason ? error.error.reason : '',
status: error.status
};
return throwError(error);
}));
}));
Ok i am updating my answer, You cannot update the request or response in an asynchronous service, you have to update the request synchronously like this
export class UseAsyncServiceInterceptor implements HttpInterceptor {
constructor( private asyncService: AsyncService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// make apply logic function synchronous
this.someService.applyLogic(req).subscribe((modifiedReq) => {
const newReq = req.clone(modifiedReq);
// do not return it here because its a callback function
});
return next.handle(newReq); // return it here
}
}
I think that there is a issue about the reactive flow. The method intercept expects to return an Observable and you have to flatten your async result with the Observable returned by next.handle
Try this
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return this.asyncService.applyLogic(req).mergeMap((modifiedReq)=> {
const newReq = req.clone(modifiedReq);
return next.handle(newReq);
});
}
You could also use switchMap instead of mergeMap
If you need to invoke an async function within interceptor then the following approach can be followed using the rxjs
from
operator.
import { MyAuth} from './myauth'
import { from } from 'rxjs'
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: MyAuth) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
// convert promise to observable using 'from' operator
return from(this.handle(req, next))
}
async handle(req: HttpRequest<any>, next: HttpHandler) {
// if your getAuthToken() function declared as "async getAuthToken() {}"
await this.auth.getAuthToken()
// if your getAuthToken() function declared to return an observable then you can use
// await this.auth.getAuthToken().toPromise()
const authReq = req.clone({
setHeaders: {
Authorization: authToken
}
})
// Important: Note the .toPromise()
return next.handle(authReq).toPromise()
}
}
If I get your question right than you can intercept your request using deffer
module.factory('myInterceptor', ['$q', 'someAsyncService', function($q, someAsyncService) {
var requestInterceptor = {
request: function(config) {
var deferred = $q.defer();
someAsyncService.doAsyncOperation().then(function() {
// Asynchronous operation succeeded, modify config accordingly
...
deferred.resolve(config);
}, function() {
// Asynchronous operation failed, modify config accordingly
...
deferred.resolve(config);
});
return deferred.promise;
}
};
return requestInterceptor;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
}]);
I am using an async method in my interceptor like this:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
public constructor(private userService: UserService) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return from(this.handleAccess(req, next));
}
private async handleAccess(req: HttpRequest<any>, next: HttpHandler):
Promise<HttpEvent<any>> {
const user: User = await this.userService.getUser();
const changedReq = req.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
'X-API-KEY': user.apiKey,
})
});
return next.handle(changedReq).toPromise();
}
}