Angular emphasizes the importance of RxJS, which requires a shift in our approach to services, methods, and variables.
Let's focus on the AuthService
.
The AuthService
communicates with the backend to verify the user's authentication status. The AuthGuard
depends on this service for its functionality. Angular expects specific return types within the canActivate
syntax:
Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
Currently, the AuthGuard
returns boolean | UrlTree
, but it can also return
Observable<boolean | UrlTree>
. This leads us to an important realization. While the
AuthService
internally uses an
Observable
, it does not pass it along. Let's make some adjustments.
export class AuthService {
private apiUrl = environment.api_uri;
constructor(private http: HttpClient) { }
public authorize(): Observable<boolean> {
return this.http.get(this.apiUrl+'/auth')
.pipe(
map(data => {
let authorized = .... // add your logic here
return authorized;
}),
catchError(error => {
return of(false);
}));
}
}
By modifying the AuthService
to return an Observable
, we can apply additional operators and utilize it within the AuthGuard
.
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router){}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.auth.authorize().pipe(
map(isAuthorized => isAuthorized || this.router.parseUrl("/403"))
);
}
}
This adjustment transforms the service into a stateless entity that functions independently upon method calls.
Sometimes, services require data storage for new entities to access past information. To address this, we introduce concepts like Subject
and BehaviorSubject
, or leverage the shareReplay
operator for efficient data handling.
For further insights, visit this link: here
An RxJS Subject facilitates multicasting values to multiple Observers, unlike regular unicast Observables where each Observer initiates a separate execution of the Observable.
Implementing a Subject
as outlined in the documentation:
const subject = new Subject<number>();
const subscriber1 = subject.subscribe(val => console.log(val))
const subscriber2 = subject.subscribe(val => console.log(val))
// Triggers callbacks of the above subscribers
subject.next(5);
However, latecomers will miss previous emissions, limiting their accessibility to the last emitted value.
const subscriber3 = subject.subscribe(val => console.log(val))
To enable newcomers to retrieve previous values, consider implementing a BehaviorSubject
.
Visit this resource for more details: here
const subject = new BehaviorSubject(123);
subject.subscribe(console.log);
subject.subscribe(console.log);
subject.next(456);
subject.subscribe(console.log);
subject.next(789);
Utilizing BehaviorSubject
ensures initial values are accessible by new subscribers. However, for scenario involving static data shared amongst components without modification, employing shareReplay
becomes instrumental.
Refactoring the AuthService
involves creating a member variable isAuthorized
encapsulating the HTTP call with error handling wrapped inside a shareReplay
operator.
export class AuthService {
private apiUrl = environment.api_uri;
private isAuthorized = this.http.get(this.apiUrl+'/auth')
.pipe(
map(data => {
let authorized = .... // add your logic here
return authorized;
}),
catchError(error => {
return of(false);
}),
shareReplay()
);
constructor(private http: HttpClient) { }
}
The usage remains consistent regardless of repetition, ensuring the singular execution of the underlying HTTP request within the service is maintained.
authService.isAuthorized.subscribe(_ => .....)