fix: serialize string payloads as JSON in reply.send#6296
fix: serialize string payloads as JSON in reply.send#6296kamalkumar789 wants to merge 7 commits intofastify:mainfrom
Conversation
lib/reply.js
Outdated
| return this | ||
| if (typeof payload === 'string') { | ||
| const contentType = this[kReplyHeaders]['content-type'] | ||
| if (contentType && contentType.startsWith('application/json')) { |
There was a problem hiding this comment.
| if (contentType && contentType.startsWith('application/json')) { | |
| if (contentType?.startsWith('application/json')) { |
lib/reply.js
Outdated
| if (typeof payload !== 'string') { | ||
| preSerializationHook(this, payload) | ||
| return this | ||
| if (typeof payload === 'string') { |
There was a problem hiding this comment.
| if (typeof payload === 'string') { | |
| if (typeof payload === 'string' && payload.length) { |
lib/reply.js
Outdated
| if (!(payload.startsWith('"') && payload.endsWith('"'))) { | ||
| payload = JSON.stringify(payload) | ||
| } |
There was a problem hiding this comment.
Not sure about this, is this restoring some functionality?
| if (!(payload.startsWith('"') && payload.endsWith('"'))) { | |
| payload = JSON.stringify(payload) | |
| } | |
| if (!(payload[0] === '"' && payload[payload.length - 1] === '"')) { | |
| payload = JSON.stringify(payload) | |
| } |
There was a problem hiding this comment.
This line restores the intended behavior so that strings are now correctly serialized if the content type is JSON.
|
The bug is fixed and tested. No need to update documentation. Will be tackled in reply.js. |
| } | ||
| } | ||
|
|
||
| if (this[kReplySerializer] !== null && typeof payload === 'string' && payload.length) { |
There was a problem hiding this comment.
I think it doesn't prevent double stringify.
You are updating the payload and the next if will serialize it again because the serializer is not empty.
There was a problem hiding this comment.
I think yes, you are right, but it can be solved with some logic. Let me push new code.
|
It's fixing the problem of double stringify in any way. |
| if (contentType?.startsWith('application/json')) { | ||
| // Avoid double stringify if payload is not already JSON string | ||
| if (!(payload[0] === '"' && payload[payload.length - 1] === '"')) { | ||
| preSerializationHook(this, payload) |
There was a problem hiding this comment.
this is an async stuff, we can't fork the logic here.
we need to reshape a bit the code to find the best place to add this check
There was a problem hiding this comment.
If you think this logic or check is fine, can you suggest where I can put or make a separate async function?
There was a problem hiding this comment.
Will check it for sure - I thought the fix could be easier by it is slippery
|
I tested coverage on main (server.js and fastify/lib) and it’s already below 100%. Regarding the new logic I added: it introduces an inner if that only runs when the payload is a non-empty string, content-type starts with application/json, and the string is not already quoted. Covering this would require adding a new test case specifically for this scenario, which I haven’t added. Also, the CI workflow failed during pnpm/action-setup with a self-installer error (Error: Something went wrong, self-installer exits with code 1). This appears unrelated to my changes and may need attention from maintainers. |
lib/reply.js
Outdated
|
|
||
| // Check if a serializer exists and payload is a non-empty string | ||
| if (this[kReplySerializer] !== null && typeof payload === 'string' && payload.length) { | ||
| if (contentType?.startsWith('application/json')) { |
There was a problem hiding this comment.
Changed to use indexOf instead of startsWith for more robust content-type checking.
This fix addresses the issue with the reply.send(string) does not serialize strings as JSON even when the Content-Type is set to application/json. Previously, Fastify would send the string raw, which did not match the documented behavior. The change ensures that if the payload is a string and the content type is JSON, it is properly wrapped with quotes using JSON.stringify, while avoiding double serialization if the string is already in JSON format. This restores the expected behavior without affecting other payload types or custom serializers.
after calling this,
reply
.type('application/json; charset=utf-8')
.send("Hello")
Fastify will automatically serialize "Hello" as JSON (""Hello"" in the response body) behind the scenes. There’s no need for the user to manually call JSON.stringify or set a custom serializer—the condition you added handles it.
Fix is in reply.js