33

In my NestJS application I want to return the result of an http call.

Following the example of the NestJS HTTP module, what I'm doing is simply:

import { Controller, HttpService, Post } from '@nestjs/common';
import { AxiosResponse } from '@nestjs/common/http/interfaces/axios.interfaces';
import { Observable } from 'rxjs/internal/Observable';

@Controller('authenticate')
export class AuthController {

  constructor(private readonly httpService: HttpService) {}

  @Post()
  authenticate(): Observable<AxiosResponse<any>> {
    return this.httpService.post(...);
  }
}

However from the client I'm getting 500 and the server console is saying:

TypeError: Converting circular structure to JSON at JSON.stringify () at stringify (/Users/francesco.borzi/sources/business-controller-rewrite/node_modules/express/lib/response.js:1119:12) at ServerResponse.json (/Users/francesco.borzi/sources/business-controller-rewrite/node_modules/express/lib/response.js:260:14) at ExpressAdapter.reply (/Users/francesco.borzi/sources/business-controller-rewrite/node_modules/@nestjs/core/adapters/express-adapter.js:41:52) at RouterResponseController.apply (/Users/francesco.borzi/sources/business-controller-rewrite/node_modules/@nestjs/core/router/router-response-controller.js:11:36) at at process._tickCallback (internal/process/next_tick.js:182:7)

Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252

4 Answers4

56

This issue comes from the axios library. In order to fix that, you have to pull out the data property:

return this.httpService.post(...)
  .pipe(
    map(response => response.data),
  );
Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252
Kamil Myśliwiec
  • 8,548
  • 2
  • 34
  • 33
11

The problem seems to stem from the fact that we are trying to return a Response object directly, and that is circular by nature. I'm not sure of the correct way to implement this, but I was able to get around it by using axios directly, unwrapping the promise and returning just the data.

@Post('login')
  async authenticateUser(@Body() LoginDto) {
    const params = JSON.stringify(LoginDto);

    return await axios.post('https://api.example.com/authenticate_user',
      params,
      {
        headers: {
          'Content-Type': 'application/json',
        },
      }).then((res) => {
          return res.data;
    });
}

UPDATE

I realized I could just do the same thing to the Observable being returned from the httpService using the new rxjs pipe method, so that's probably the better way to do it.

@Post('login')
async authenticateUser(@Body() LoginDto) {
    const params = JSON.stringify(LoginDto);

    return this.httpService.post('https://api.example.com/authenticate_user',
      params,
      {
        headers: {
          'Content-Type': 'application/json',
        },
      }).pipe(map((res) => {
    return res.data;
  }));
}
andyrue
  • 903
  • 10
  • 24
0

If you are looking for HTTP Data, HTTP Status code and wanted to convert an observable to a promise using firstValueFrom ('rxjs')

const responseData = await firstValueFrom(
        this.httpService.post(url, data, config).pipe(map((response) => [response.data, response.status])),
      );
iravinandan
  • 659
  • 6
  • 16
0

For those of us who are familiar with Axios and want to stick to that, here's the solution I can suggest:

@Injectable()
export class HttpService {
 constructor(private readonly http: HttpService){}

 fetch(url, params) {
  return this.http.axiosRef.get(url, params)
  }

}
giles
  • 85
  • 1
  • 9