How to rethrow errors of HttpService call with NestJS?
Asked Answered
E

2

25

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.

Edlyn answered 9/4, 2019 at 21:33 Comment(0)
C
47

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.

Chartography answered 9/4, 2019 at 22:54 Comment(4)
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".Centonze
@JimWharton You should be able to customize this behavior with validateStatus, see github.com/axios/axios#handling-errorsChartography
Oh that's brilliant. Thanks for that!Centonze
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!Centonze
M
1

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;
    }
}
Mocambique answered 19/8, 2023 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.