Hikaru Shindo
Hikaru Shindo

Reputation: 2923

NestJS Controller always return 201 created when it works with httpclient

I'm new to the NestJS. I want to make my service to connect with 3rd party API. When I try to call my API, it always return 201 Created with no result in http body,

Here is my service,

@Injectable()
export class AuthService {
  constructor(
    private readonly httpService: HttpService, 
    private configService: ConfigService
  ) {}

  authWithHrService(authDto:AuthDto): Observable<any> {
    const host = this.configService.get<string>('HR_HOST');
    const port = this.configService.get<string>('HR_PORT');
    return this.httpService.post(`${host}:${port}/hr/authen`, authDto).pipe(
      map(response => response.data)
    );

  }

}

And here is my Controller (which always return 201),

@Controller('auth')
export class AuthController {
  private readonly logger = new Logger();
  constructor(private readonly authService: AuthService) {}

  @Post('')
  authen(@Body() req: AuthDto) {

    this.authService.authWithHrService(req).subscribe({
      next: (data) => {
        this.logger.log(`---> authResult :: ${JSON.stringify(data)}`); //This log show result successfully.
        return data;
      },
      error: (err) => {
        throw new HttpException("Authentication Failed.", HttpStatus.UNAUTHORIZED);
      }
    });

  }

}

Based on the Controller, even the result will be in the error case, it still returns 201 Created instead of 401

enter image description here

Please help.

Upvotes: 1

Views: 846

Answers (2)

Robin Thomas
Robin Thomas

Reputation: 4146

Post requests always return 201 response code as default in NestJS.

Furthermore, the response's status code is always 200 by default, except for > POST requests which use 201

https://docs.nestjs.com/controllers

You can change this default behaviour using @HttpCode decorator:

import { HttpCode, HttpStatus } from '@nestjs/common';

// ...rest of your code

@Controller('auth')
export class AuthController {
    @Post('')
    @HttpCode(HttpStatus.OK)
    authen(@Body() req: AuthDto) {
        // your request body
    }
}

Second, you don't have to subscribe to handle the Observable. You can return that from the controller.

@Post('')
authen(@Body() req: AuthDto) {
    return this.authService.authWithHrService(req);
}

If you instead want to return a custom error, you can change the code to:

@Post('')
async authen(@Body() req: AuthDto) {
    try {
        const data = await this.authService.authWithHrService(req).toPromise();
        this.logger.log(`---> authResult :: ${JSON.stringify(data)}`);

        return data;
    } catch (err) {
        throw new HttpException("Authentication Failed.", HttpStatus.UNAUTHORIZED);
    }
}

Upvotes: 1

Jay McDoniel
Jay McDoniel

Reputation: 70450

You don't return anything from the controller, and you don't use the library-specific approach so Nest will see the method call was successful. If you want Nest to wait, either return the observable (without subscribing to it) or inject @Res() and handle sending res.status().send() yourself if you want to keep subscribing yourself

Upvotes: 1

Related Questions