Attempting to intercept a 401 error in an HTTP interceptor, I aim to refresh my session and then retry the initial request

My goal is to intercept responses returning from the /api, catching them if they are a 401 error, executing a refresh session action, and then retrying the original HTTP call again (while also preventing it from infinitely looping if another 401 error occurs).

In the code below, I believe I am triggering the request using the http handler, subscribing to its events, and handling the case where it fails on a 401 error by refreshing the session and returning an observable of the cloned request being processed by the handler.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!request.url.startsWith('/api')) {
        return next.handle(request)
    }

    const cloned = request.clone()
    return next.handle(request)
        .pipe(
            catchError((error: any) => {
                if (error.status !== 401) {
                    return throwError(error)
                }
                return from(this.sessionService.refresh())
                    .pipe(map(() => next.handle(cloned)))
            })
        )
}

Do you have any suggestions on how I can achieve my objective?

Answer №1

Here is a code snippet that may have a few syntax errors due to writing it on mobile:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!request.url.startsWith('/api')) {
    return next.handle(request)
}

const cloned = request.clone()
return next.handle(request)
    .do((event: HttpEvent<any>) =>
        return from(this.sessionService.refresh())
               .pipe(map(() => next.handle(cloned)))
        }), (err: any) => {
             if (err instanceof HttpResponse) {
                  if(err.status === 401){
                       return throwError(error);
                  }
        }
    )
}

Answer №2

The solution involved using switctMap instead of map

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
{
    if (!request.url.startsWith('/api')) {
        return next.handle(request)
    }

    const cloned = request.clone()
    return next.handle(request)
        .pipe(
            catchError((error: any) => {
                if (error.status !== 401) {
                    return throwError(error)
                }
                return from(this.sessionService.refresh())
                    .pipe(switchMap(() => next.handle(cloned)))
        })
    )
}

However, I decided to take a different route by implementing a pre-request session check and injecting a refresh action when needed.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (
        !request.url.startsWith('/api') || 
        this.sessionService.isValid
    ) {
        return next.handle(request)
    }

    return from(this.sessionService.refresh())
        .pipe(switchMap(() => next.handle(request)))
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason for the return of undefined with getElementsByClassName() in puppeteer?

Currently, I am utilizing puppeteer to fetch certain elements from a webpage, specifically class items (divs). Although I understand that getElementsByClassName returns a list that needs to be looped through, the function always returns undefined for me, e ...

Using ngrx to automatically update data upon subscription

Background The technology stack I am using for my application includes Angular 4.x, ngrx 4.x, and rxjs 5.4.x. Data is retrieved from a websocket as well as a RESTful API in order to share it between multiple components through ngrx. Currently, data is ref ...

What methods does VS Code use to display type errors in TypeScript given that TypeScript requires compilation?

TypeScript is a language known for being statically typed, giving it the ability to verify types during the compilation process and translate the code into JavaScript. Considering this, how is it possible for VS Code to detect type errors without the code ...

Using Angular, create mat-checkbox components that are dynamically generated and bound using

In my Offer class, I have a property called "units" which is an array of objects. export class Offer { public propertyA: string; public propertyB: string; public units: Unit[]; } export class Unit { public code: string, public name: ...

What steps can I take to troubleshoot and fix the issue of a Duplicate identifier 'DateType' error during the React/Typescript building process

Utilizing the MUI library, I have also installed the @mui/x-date-pickers library. In order for my datepicker component to function properly, I need to install the @date-io/date-fns/ library as well. However, upon running yarn build, I encountered the fol ...

Conditioning types for uninitialized objects

Is there a way to create a conditional type that can determine if an object is empty? For instance: function test<T>(a: T): T extends {} ? string : never { return null } let o1: {} let o2: { fox? } let o3: { fox } test(o1) ...

Here is a way to return a 400 response in `express.js` when the JSON request body is invalid

How can I make my application send a response with status code 400 instead of throwing an error if the request body contains invalid JSON? import express from 'express' app.use(express.urlencoded({ extended: false })) app.use(express.json()) ...

How to determine the presence of 'document' in Typecsript and NextJS

Incorporating NextJS means some server-side code rendering, which I can manage. However, I'm facing a challenge when trying to check for set cookies. I attempted: !!document && !!document.cookie as well as document !== undefined && ...

Error: zsh is unable to locate the command, even after defining it in package.json bin and installing it globally

I attempted to create a command-line application using TypeScript. Below is the code I have written: //package.json { "name": "jihea-cli", "version": "1.0.0", "description": "", "main": "index.ts", "bin": { "cli": "./bin/index.ts" }, // ...

The element at index '0' is not defined for the data type 'number | [number, number]'

In my current project, I have a component named ComponentA which has a defined interface. Here is the snippet of the interface: interface A1 { isSingle: true; value: number; } interface A2 { isSingle: false; value: [number, number]; } exp ...

Limiting File Access for a Google Cloud Platform Bucket Using Node.js

Below is the code for my fileUploadService: import crypto from 'crypto'; var storage = require('@google-cloud/storage')(); uploadFile(req, bucket, next) { if (!req.file) { retur ...

Angular's custom validator consistently returns a null value

I need help with validating the uniqueness of a username field in a form where an administrator can create a new user. I have implemented a uniqueUserNameValidator function for this purpose, but it always returns null. I suspect that the issue lies in the ...

Having trouble retrieving the date value from a datepicker in Angular ngForm

I am struggling to fetch a value from the mat-datepicker in my Angular project. Whenever I try, it returns as undefined. I have implemented ngForm and ngModel, but I seem to have made a mistake somewhere. <form #f="ngForm" (ngSubmit)="registerClient(f. ...

Implement social login functionality in your Angular 12 application

I have recently started working with Angular, and for the past week, I have been encountering issues while trying to install the angularx-social-login package in my project. My project is using Angular 12 because of the pro version of MDBootstrap Angular 4 ...

What is the process of encapsulating a callback function within another callback function and invoking it from there?

Here is the code snippet I am working with: var me = this; gapi.auth.authorize({ client_id: client, scope: scope, immediate: true }, function (authResult: any) { if (authResult && !authResult.error) { me ...

Why does the Change Detection problem persist even when using On Push with the same object reference?

After a recent discussion on Angular Change detection, I believed I had a solid understanding. However, my confidence wavered when I encountered this issue: Why is change detection not happening here when [value] changed? To further illustrate the problem ...

The combination of Ace editor and Angular 2 leads to synchronization issues with Protractor

Currently, I am in the process of developing a new application using Angular 2 (version 2.0.0) and angular-cli (version 1.0.0-beta.14). In order to integrate Ace editor into my project, I have utilized an Angular 2 directive as per the guidelines provided ...

Efficient management of npm dependencies versioning using Git workflow with Angular

In my Angular project, we combine multiple locally created artifacts that are published to the npm repository. Within the "dependencies" section of my app's package.json file, I include the following: "@k/e-lib": "^0.3.0", "@k/et-lib": "^0.3 ...

Problem encountered in a simple Jest unit test - Unexpected identifier: _Object$defineProperty from babel-runtime

Struggling with a basic initial test in enzyme and Jest during unit testing. The "renders without crashing" test is failing, as depicted here: https://i.stack.imgur.com/5LvSG.png Tried various solutions like: "exclude": "/node_modules/" in tsconfig "t ...

What is the purpose of exporting both a class and a namespace under the same name?

While exploring some code, I came across a situation where a class and a namespace with identical names were exported from a module. It seems like the person who wrote this code knew what they were doing, but it raised some questions for me. Could you shed ...