Ignore null properties in the JSON response
hershmire opened this issue · 8 comments
You have already researched for similar issues?
I have searched around and have only found this StackOverflow question from over 2 years ago which was never answered.
What are you trying to achieve, or the steps to reproduce?
I would like to have the Fastify reply ignore sending back any properties that are null
. Some of the endpoints I'm writing are for both admin and non-admin users. Admin users may have some additional properties on a resource response that I would prefer not to even make known if the response is from a non-admin. Wondering if there's any out-of-the-box way to do this.
Example Admin response:
{
"firstName": "John",
"lastName": "Doe",
"signatureUrl": "https://example.com/signatures/123/signature.png"
}
Example Non-Admin response:
{
"firstName": "John",
"lastName": "Doe"
}
What was the result you received?
Currently I'm getting the following for the Non-Admin user since the signatureUrl
field is nullable. I would like to not show this field at all to this type of user to reduce the overall payload size and not expose additional information that they are privy to.
Example Admin response:
{
"firstName": "John",
"lastName": "Doe",
"signatureUrl": null
}
What did you expect?
Context
- node version: 20
- fastify version: >=4.28
- os: Mac
I'm using Typescript with Typebox.
I would say just send what you expect.
If you don't need that property, don't send it.
You may also use preSerialization
hooks to remove the null value properties, but it is expected to slow things down.
fastify.addHook('preSerialization', (_request, _reply, payload, done) => {
// this is a loose check only, update what your needs
if (typeof payload === 'object' && payload !== null && !Array.isArray(payload)) {
done(null, Object.fromEntries(Object.entries(payload).filter(([_, v]) => v != null)))
}
done(null, payload)
})
+1 on @climba03003 point.
Remember that null
is a valid value as per JSON Schema spec, so it should not be stripped if you want the serializer to be spec conformant.
As said earlier, better to not send them at all.
If you don't need that property, don't send it.
@climba03003 @metcoder95 What do you mean? Are you referring to filtering that out prior to having it go to the serializer?
My example above is a bit trivial but I have some other use cases such as providing a default (minimal) payload and allowing consumers to add more fields when providing a search param – e.g. https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-id#tab1 user.fields
.
What do you mean?
I means if you plan to send
{
"firstName": "John",
"lastName": "Doe"
}
send exactly what it is. Don't add signatureUrl
.
Are you referring to filtering that out prior to having it go to the serializer?
That is one of the solution, but I don't recommend.
Okay... That's kind of why I created this issue in the first place. It's the same endpoint but based on the type of user who's making the request and their permissions, some fields might be filtered out at the controller layer. The intention is to not have all those fields that should be filtered show up be as null
. This is not a unique question as many large APIs do this. Just curious how best to handle this within Fastify.
You have stumbled upon one of the most difficult authorization problems: field level authorization. We really can't help you design around this other than the recommendations provided so far. The serializer is doing what it should, serializing null
to null
as per spec. If you do not wish for such fields to be sent to the client, do not feed them into the serializer. Or you can provide your own serializer that is able to recognize your payloads.
This is not a unique question as many large APIs do this. Just curious how best to handle this within Fastify.
Yes, it is. But most of the database support field selection, which is what similar to filter out unwanted field.
For example, MySQL can SELECT <wanted field> FROM <database>
, MongoDB can project the wanted field only.
That's why I said you should send what you expected.
You can also do it in reverse way seen the optional fields is provided through query already.
In this way, you can send the expected result and prevent using value reassignment or delete
.
function copy ( obj, wantedFields ) {
const result = []
for(const field of wantedFields) {
result[field] = obj[field]
}
return result
}
The recommendation should based on what tools you choose and application design (which may not be public).
In this particular case, I would recommend you to find consultation services outside.
I see someone raised a PR in fast-json-stringify
with your request 3 weeks ago.
So, I would close the help issue in favor of it.
Refs fastify/fast-json-stringify#731