Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] JSON double-encoding when using res.json() and validator.responseValidation #367

Open
Mick605 opened this issue Mar 4, 2023 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@Mick605
Copy link
Contributor

Mick605 commented Mar 4, 2023

Describe the bug

When using res.json() to create a response while the configuration validator.responseValidation is true, the content of the response gets double encoded in JSON.

To Reproduce

Steps to reproduce the behavior:

  1. Create a controller with res.json(), such as:
export function listPets(req, res) {
    res.json({
        message: 'This is a mockup controller'
    });
}
  1. Set the validator.responseValidation configuration to false
  2. Call the API endpoint. The result is a valid JSON object:
{
  "message": "This is a mockup controller"
}
  1. Set the validator.responseValidation configuration to true
  2. Call the API endpoint again. The JSON object got double-encoded:
"{\"message\":\"This is a mockup controller\"}"

Expected behavior

The result should not be JSON encoded twice when using res.json()

Notes

  • The problem only occurs when using res.json() to generate the response, not when using res.send().
  • This problem leads to validation errors, because the double encoded string is not matching the provided schema:
[oas-tools] WARN: Wrong data in response.
Validation failed at #/type > must be object
@Mick605 Mick605 added the bug Something isn't working label Mar 4, 2023
@Mick605
Copy link
Contributor Author

Mick605 commented Mar 4, 2023

The problem seems to come from the interception of the res.send function done in oas-validator.js, line 102

  /* Intercepts response */
  const oldSend = res.send;
  res.send = function send(data) {
    // here, data parameter can be either object or string
   ...
  }

The data parameter can either be of type object or string, depending on the way the response is generated:

  • when using res.send(object), data will be an object
  • when using res.json(object), data will be a JSON encoded string

It seems that there is not enough information in the current interceptor to differenciate these cases. Testing if data looks like a JSON encoded string is not a solution because someone could want to use res.send() to send an already JSON encoded string.

Intercepting also the res.json method in oas-validator.js seems to be tricky, because the original res.send from Express calls res.json internally in some cases, and res.json calls res.send internally too...

In my opinion, the interception should be made at a lower level, to avoid these problems. The interception itself could be made with an external library, such as express-interceptor. Using a low-level interceptor also has the benefit to allow more use cases of response generation, such as calling res.write() directly.

@alesancor1 alesancor1 self-assigned this Mar 6, 2023
@alesancor1
Copy link
Member

Hello, Mick, I agree with what you say about intercepting responses at a lower level. Ideally, it is the res.write( ) method what should be overriden, since it is what writes the data to the stream before calling res.end( ). I'll study how express-interceptor works and try to fix that.

@agnoam
Copy link

agnoam commented Mar 30, 2023

Hey, any news about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: To Do
Development

No branches or pull requests

3 participants