typestack/routing-controllers

fix: Unable to parse response body the throw the HTTP error

Closed this issue · 9 comments

Description

According the documentation,

If you want to return errors with specific error codes, there is an easy way:

@Get("/users/:id")
getOne(@Param("id") id: number) {

    const user = this.userRepository.findOneById(id);
    if (!user)
        throw new NotFoundError(`User was not found.`); // message is optional

    return user;
}

Now, when user won't be found with requested id, response will be with http status code 404 and following content:

{
  "name": "NotFoundError",
  "message": "User was not found."
}

Source

Unfortunately, when I tried to throw the BadRequestError, I can not access to response data:

Image

According to response headers, the Content-Type has text/html; charset=utf-8 type:

Image

Same as browser developer tools can not parse it, the text() method of fetch API fails.

Minimal code-snippet showcasing the problem

import {
  Controller,
  Post,
  BadRequestError
} from "routing-controllers";


@Controller()
export default class SampleController {

  @Post("/api/sample")
  protected sampleHandler(): void {
    throw new BadRequestError("Sample");
  }

}

Expected behavior

The response with content-type: application/json; charset=utf-8 header and following content will be submitted to client:

{
  "name": "BadRequestError",
  "message": "Sample"
}

Actual behavior

The response has content-type: text/html; charset=utf-8 header and non-parseable content.

Could you try @JsonController instead of @Controller?

@attilaorosz

Thank you for the answer.

Could you try @JsonController instead of @Controller?

I have tried @JsonController , but nothing has changed.
Well, even it works, my controllers returns both JSON and HTML, so it was not the solution.l

I am using option classTransformer: false, maybe it is related?
My application will not work if I'll enable it.

I don't really understand how it could return both html and json. Could you setup a simple reproduction repo for this so I can check it?

@attilaorosz

Could you setup a simple reproduction repo for this so I can check it?

It will take some some to boil down my app which is production-ready, but if you need to for investigation, I'll prepare it.
Please keep this issue opened.

I don't really understand how it could return both html and json.

Simply if MVC application also has REST API.

@Controller
class BlogPostController {

  /* === MVC ======================== */
  @View("views/BlogPost.hbs")
  protected renderBlogPostPage(): Promise<BlogPost> {
     // ... Transactions with DB
     return {
        // ...
     }
  }

  /* === REST ======================== */
  protected addBlogPost(): Promise<void> {
    // ... Transactions with DB
    // Once done frontend can redirect to blog post page thus does not need the response data
  }

}

@attilaorosz

Sorry for keep you waiting.
Fortunately, the creating of reproduction have not took too much time, even I was not need to boil done my initial project.

Here is the reproduction:
https://github.com/TokugawaTakeshi/Issue-RoutingControllersErrorData

As you can see, there is still Content-Type: text/html; charset=utf-8 among the response headers while the response body is even not the HTML:

Image

Image

Ok I think I understand your problem now.
The thing is, if you don't use @JsonController, the response type will not be set to json. If you would like to have a mixed response type controller you can do it manually.

Keep your view methods html, so @Controller is sufficient.

For the json methods, inject @Res() into the method params, constuct your response as it was a normal express response, then return the res object from the method.

  @Get('/api/sample')
  protected sampleHandlerJson(@Res() res: Response) {
    res.status(404);
    res.json();

    return res;
  }

  @Get('/api/sample/working')
  protected sampleHandlerJsonWithoutError(@Res() res: Response) {
    res.json({myParam: 'myValue'});

    return res;
  }

Alternatively, if you only want to use json for errors, you can do this response handling in the error handler.

O'K, thank you for the support.
If above API is intentional, I'll close this issue.

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.