/http-interceptors

The Web apps in this monorepo make HTTP requests and require uniform consistency in how they are executed and handled. This monorepo demonstrates the same app written with Angular and with Svelte. Each app uses HTTP interceptors. The Angular app uses HttpClient and its interceptors while the Svelte app uses Axios and its interceptors.

Primary LanguageTypeScriptMIT LicenseMIT

Tour of Heroes, the Movie Edition - Http Interceptors Demo

The Web apps in this monorepo make HTTP requests and require uniform consistency in how they are executed and handled.

This monorepo demonstrates the same app written with Angular and with Svelte. Each app uses HTTP interceptors. The Angular app uses HttpClient and its interceptors while the Svelte app uses Axios and its interceptors.

by John Papa

Getting Started

  1. Clone this repository

    git clone https://github.com/johnpapa/http-interceptors.git tour
    cd tour
  2. Choose your app

    cd angular-app
    # or
    cd svelte-app
  3. Install the npm packages

    npm install
  4. Run the app

    npm run full-stack

Apps in this Repository

There are several apps in this repository.

Folder Description
angular-http-hard-way Angular app using HttpClient directly. Adds headers, invokes a busy/progress indicator, and handles authentication errors without interceptors.
angular-app Angular app using Http Interceptors.
svelte-app Svelte app using Axios Interceptors.

What's in the App

Here is a list of the features in each app (other than the angular-http-hard-way app)

  • Pages for home, list of movies, heroes and villains
  • HTTP Interceptors
  • API
    • json-server is a backend. No database needed.
    • json-server-auth provides signin/out authentication and authorization routes.
    • App served on one port which can access API on another port proxy or CORS)
    • HTTP - Uses most common client http libraries for each framework
    • API routes are restricted to those who sign in except movies
    • API route movies is readonly to all (no sign in required)
  • Viewing/Editing Pages
    • Home and Movies pages are read-only, and require no authentication
    • Heroes and Villains pages support editing, and require authenticatation
  • State/Store - Uses a store for state management
  • Styling with Bulma, same css in each app, and Font Awesome

Interceptors

Sequence is super important with interceptors. They flow in sequence for requests, and then in the opposite order for responses.

The flow for Axios Interceptors and for Angulars Http Interceptors is different.

Angular Http Interceptor Flow

Angular's interceptors flow in the order you provide them. If you provide interceptors A, then B, then C, then requests will flow in A->B->C and responses will flow out C->B->A.

// Requests will flow in A->B->C and responses will flow out C->B->A.
export const httpInterceptorProviders = [
  /**
   *  Log Http:
   *    This logs all HTTP traffic.
   *    Do this first so it can log the Http call happening in and out (last).
   */
  addInterceptor(LogHttpInterceptor),
  /**
   * ReadOnly:
   *    This makes sure that HTTP POST, PUT and DELETE are not allowed if the
   *    user does not have permission. If they do not, then it cancels the request.
   *    Do this early, before we add headers, get busy, or execute the request.
   */
  addInterceptor(ReadOnlyInterceptor),
  /**
   SSL:
   *    Ensure SSL by making calls that use http instead use https.
   */
  addInterceptor(EnsureSSLInterceptor),
  /**
   * Auth:
   *    Add the authentication headers.
   */
  addInterceptor(AuthInterceptor),
  /**
   * CSRF:
   *    Add the CSRF headers.
   */
  addInterceptor(CSRFInterceptor),
  /**
   *  Log headers:
   *    Log all headers.
   *    Must come after the headers are stuffed and before the request is made.
   */
  addInterceptor(LogHeadersInterceptor),
  /**
   *  Busy:
   *    Enable and increment the count of HTTP requests, which can be used to show a busy indicator.
   *    Also decrement the count when responses are received, to eventually turn off the busy indicator.
   *    This must happen once it is certain a request will be made,
   *    and right after the response is received.
   */
  addInterceptor(BusyInterceptor),
  /**
   * Transform Response:
   *    Transform the response, making it easier to consume.
   *    This could happen anywhere in this particular stream,
   *    as it operates on the response.
   */
  addInterceptor(TransformInterceptor),
];

function addInterceptor<T>(interceptor: T) {
  return {
    provide: HTTP_INTERCEPTORS,
    useClass: interceptor,
    multi: true,
  };
}

Axios Interceptor Flow

Axios's interceptors flow in the reverse of the order you provide them. If you provide interceptors A, then B, then C, then requests will flow in C->B->A and responses will flow out A->B->C.

Therefore, it is important to add them in the reverse of the order you want them to execute.

... but ...

This might make the code confusing to read, since we think of the order that we add them as being how they are applied. So we:

  1. add the functions that apply the interceptors to an array in the order we want them to be applied
  2. reverse the array, to get them how Axios interceptors wants them
  3. execute the functions that apply the interceptors
export function applyHttpInterceptors() {
  globalHeaders();

  const interceptors = [
    /**
     *  Log Http:
     *    This logs all HTTP traffic.
     *    Do this first so it can log the Http call happening in and out (last).
     */
    logHttpInterceptor,
    /**
     * ReadOnly:
     *    This makes sure that HTTP POST, PUT and DELETE are not allowed if the
     *    user does not have permission. If they do not, then it cancels the request.
     *    Do this early, before we add headers, get busy, or execute the request.
     */
    readOnlyInterceptor,
    /**
       SSL:
     *    Ensure SSL by making calls that use http instead use https.
     */
    ensureSSLInterceptor,
    /**
     * Auth:
     *    Add the authentication headers.
     */
    authInterceptor,
    /**
     * CSRF:
     *    Add the CSRF headers.
     */
    csrfInterceptor,
    /**
     *  Log headers:
     *    Log all headers.
     *    Must come after the headers are stuffed and before the request is made.
     */
    logHeadersInterceptor,
    /**
     *  Busy:
     *    Enable and increment the count of HTTP requests, which can be used to show a busy indicator.
     *    Also decrement the count when responses are received, to eventually turn off the busy indicator.
     *    This must happen once it is certain a request will be made,
     *    and right after the response is received.
     */
    busyInterceptor,
    /**
     * Transform Response:
     *    Transform the response, making it easier to consume.
     *    This could happen anywhere in this particular stream,
     *    as it operates on the response.
     */
    transformInterceptor,
  ];

  interceptors.reverse().forEach((f) => f());
}

Problems or Suggestions

Open an issue here

Resources