22

I am using NestJS to essentially proxy a request to another api using the HttpService (an observable wrapped Axios library). For example:

return this.httpService.post(...)
  .pipe(
    map(response => response.data),
  );

This works properly when the call is successful; however, if there's an error (4xx), how do I properly return the status and error message?

I've figured out how to do it with promises, but if possible I would like to stay within an observable.

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
Chaz
  • 3,232
  • 5
  • 19
  • 12

3 Answers3

42

You can use catchError to rethrow the exception with the corresponding status code:

import { catchError } from 'rxjs/operators';

this.httpService.get(url)
      .pipe(
        catchError(e => {
          throw new HttpException(e.response.data, e.response.status);
        }),
      );

Note that error.response might be null, see the axios docs for all error cases to check for.

Also, axios does not throw for 4xx errors as they might be expected and valid responses from the API. You can customize this behavior by setting validateStatus, see docs.

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
  • 1
    Oddly, I can send an AxiosError with a code of 401 through this pipeline and it never catches. All 400 level errors are considered a "success". – Jim Wharton May 12 '20 at 01:40
  • 3
    @JimWharton You should be able to customize this behavior with `validateStatus`, see https://github.com/axios/axios#handling-errors – Kim Kern May 12 '20 at 08:27
  • Oh that's brilliant. Thanks for that! – Jim Wharton May 12 '20 at 13:09
  • Looks like that's getting ignored. I've had to put an explicit check for status codes greater than 400 in a map inside the pipe. I throw from there. It's not ideal but, it's what I'd do with a Promise so, it's fine. Thanks! – Jim Wharton May 12 '20 at 13:24
0

Hello you can try also like this to get value with rxjs from request

const { data } = await lastValueFrom(
  this.httpService.get(`${process.env.URL}/users`, {
    headers: {
      Authorization: authorization,
    },
  }),
);
Abdulrahim Klis
  • 388
  • 3
  • 9
0

Without using rxjs:

import { AxiosResponse, isAxiosError } from 'axios';
import { lastValueFrom } from 'rxjs';
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';

@Injectable()
class YourService {
    constructor(private readonly httpService: HttpService) {}

    private async request<TRes, B = unknown>(body?: B): Promise<AxiosResponse<TRes> | null> {
        try {
            const res = await lastValueFrom(this.httpService.post<TRes>('http://localhost:3000/api', body));

            return res;
        } catch (e) {
            // Error handling here...
            if (isAxiosError(e)) {
                console.log(e.response.data);
            } else {
                console.log(e);
            }

            return null;
        }
    }

    public async sendTest() {
        const res = await this.request();

        return res?.data;
    }
}
zemil
  • 3,235
  • 2
  • 24
  • 33