Handling and validation of optional null values in JSON body
lundibundi opened this issue · comments
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Fastify version
4.26.2 / test on master
Plugin version
No response
Node.js version
20.x
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
14.2.1
Description
Currently I observe that the validation of JSON body with null
value silently passes without throwing any error even when null
is not allowed by JSON schema. And which is worse replaces that null
with default value. e.g. if field is defined as type: string
in JSON schema the value will be replaced with empty string ''
.
I've tried to provide custom ajv instance to fastify with removeAdditional: true, coerceTypes: false
but that didn't help. I guess it is not used for validation directly.
Upon testing this case with raw ajv
the results were inconsistent. With simple schema with optional fields it just silently passed the null
. With schema with anyOf
it sometimes breaks the value and removed valid fields...
So the issue might be with ajv
as well.
I've prepared a test case below similar to the ones in schema-validation.test.js
.
Steps to Reproduce
I've prepared a test case based on ones in schema-validation.test.js
.
test('Validation of optional null body params test', t => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', {
schema: {
body: {
type: 'object',
properties: {
name: { type: 'string' },
work: { type: 'string' }
},
required: ['name']
}
}
}, function (req, reply) {
reply.code(200).send(req.body)
})
fastify.inject({
method: 'POST',
payload: {
name: 'michelangelo',
work: null
},
url: '/'
}, (err, res) => {
t.error(err)
t.same(res.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'body/work must be string' })
t.equal(res.statusCode, 400)
})
})
Currently this test case fails with the following:
Meaning that the work: null
gets coerced to ''
.
Expected Behavior
I'd expect the validation to either throw (because this is not valid value by JSON schema) or at least remove it from body. But not replace it with default value.
Please clarify where should I look into the fix, do you think this can be a fastify or ajv issue?
I'd gladly work on a fix once I understand where to look.
Interesting, it should throw unless nullable is enabled
This seems the correct behavior of coerceTypes
.
I've tried to provide custom ajv instance to fastify with removeAdditional: true, coerceTypes: false but that didn't help. I guess it is not used for validation directly.
How did you test those?
@mcollina thanks for absolute on point question. Looks like I didn't pass the ajv setup to the test server which caused this to happen. After that the behavior is as I expected - throw with 400.
I guess then the only question remaining is for default setup. Looking at https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/#schema-validator I assumed that coerceTypes: 'array'
is coerce arrays only
which is not correct. And that is actually coerce everything and arrays
. So resolving this now.
Adding server setup for reference:
fastify({
pluginTimeout: 25_000,
ajv: {
customOptions: {
useDefaults: true,
removeAdditional: true,
coerceTypes: false,
allErrors: false,
allowUnionTypes: true,
},
plugins: [ajvFormats, ajvKeywords],
},
});
Thanks for quick response.