Search code examples
angularrxjsangular6ngxs

how to use value from NGXS store in HttpInterceptor?


I'm pretty new to Angular. I am using Angular 6 with NGXS for state management.

My NGXS store has a user reducer whose interface is

/* src/app/store/models/user.model.ts */
export interface User {
    serverToken? : string;
    // and other unrelated stuff
}

I would like to use serverToken in Authorization header in a HttpInterceptor.

This is my current HttpInterceptor codes

import {Store, Select} from '@ngxs/store';
import {Injectable} from '@angular/core';
import {HttpInterceptor, HttpHandler, HttpRequest, HttpEvent} from '@angular/common/http';

import {Observable} from 'rxjs';
import {User} from '../store/models/user.model';

@Injectable()
export class ApiInterceptor implements HttpInterceptor {
    constructor(private store : Store) {}
    @Select()user$ : Observable < User >;

    intercept(req : HttpRequest < any >, next : HttpHandler) : Observable < HttpEvent < any >> {
        let options = {
            url: `https://base-url.com/api/${req.url}`
        };

        const serverToken = '???';
        if (serverToken) // if not empty
            options = {
                ...options,
                headers: req
                    .headers
                    .set('Authorization', `JWT ${serverToken}`)
            }

        const duplicate = req.clone(options);

        return next.handle(duplicate);
    }
}

so my question is: How to properly and elegantly use the user$ observable to get the serverToken and use it in HttpInterceptor if serverToken is not empty?


Solution

  • If you prefer a more "observable" approach, try something like:

    intercept(req : HttpRequest < any >, next : HttpHandler) : Observable < HttpEvent < any >> {
    
      return this.serverToken$.pipe(
        take(1),
        concatMap(serverToken => {
          if (serverToken) {
            options = {
              ...options,
              headers: req.headers.set('Authorization', `JWT ${serverToken}`)
            }
            const duplicate = req.clone(options);
            return next.handle(duplicate)
          } else {
            // next() without changing req
            return next(req)
          }
        }
      )
    }
    

    You will also need to define a @Selector that returns user token and @Select it from the interceptor class.

    Note: I am not familiar with HTTP interceptor but just applying the concept of chaining RxJS observables based on what I see in the signature of intercept().