in my UserService
I've got a user Observable
object which holds the UserModel
of the user logged in. For testing I've implemented inside the ngOnInit()
the login process:
this.userService.authenticate('###', '###')
.subscribe(res => console.log('authenticated'));
private userSource = new BehaviorSubject<UserModel>(null);
public user = this.userSource.asObservable();
My UserModel provides an attribtue called authKey which is used for the API auth.
In my ProjectService
I would like to do an api request; in order to do this, the api key stored in the UserModel
is necessary. It would possible just to subscribe the user attribute, but I read about avoiding to do subscriptions inside services.
Question
How can I connect this subscriptions with pipes/mapping? My approach was the following code; but that feels like bad code.
suggest(term: string): Observable<ProjectModel[]> {
return this.userSrv.user.pipe(
mergeMap((user: UserModel) => {
const options = {params: {'access-token': user.accessToken}};
return this.http.get<ProjectModel[]>(this.conf.url, options).pipe(
map(response => {
// mapping the projects ...
return projects;
})
);
})
);
}
As already stated in the previous answer, a HTTP Interceptor is best suited for your use case.
The basic idea would look like this:
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
import {mergeMap,map} from 'rxjs/operators';
import {Observable} from 'rxjs';
function isLoginRequest(req: HttpRequest<any>): boolean {
// implement
}
@Injectable()
export class AccessTokenInterceptor implements HttpInterceptor {
constructor(private readonly userService: UserService){}
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
if(isLoginRequest(req)) return next.handle(req);
return this.userService.user.pipe(
map(user => req.clone({setParams:{'access-token': user.accessToken}})),
mergeMap(req => next.handle(req))
);
}
}
Dont forget to register this interceptor as exemplified in the docs.
By using this, your original service function is reduced to:
suggest(term: string): Observable<ProjectModel[]> {
return this.http.get<ProjectModel[]>(this.conf.url).pipe(
map(response => {
// mapping the projects ...
})
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With