-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
fix: stripUnknown
should honor local explicit .unknown(false)
#3037
Conversation
strictUnknown
should honor local explicit .unknown(false)
strictUnknown
should honor local explicit .unknown(false)
strictUnknown
should honor local explicit .unknown(false)
stripUnknown
should honor local explicit .unknown(false)
Thanks, sorry for the delay. |
This change seems to break a construct that I'm using in a lot of places. When I want to allow an object to contain additional properties, but have Joi strip them out, I have: const Joi = require('joi');
const schema = Joi.object({ foo: Joi.string()} )
.unknown(false)
.options({ stripUnknown:true });
console.log(schema.validate({foo: 'abc', bar: 'def'})); With this change the validation fails: {
value: { foo: 'abc', bar: 'def' },
error: [Error [ValidationError]: "bar" is not allowed] {
_original: { foo: 'abc', bar: 'def' },
details: [ [Object] ]
}
} ... whereas before it succeeded and stripped out { value: { foo: 'abc' } } I guess the reason why I'm using that construct is that I've liberally added I'll adapt my code, but this change probably shouldn't have gone out in a patch. |
I feared this would happen, but your schema is a bit self-contradictory, explicitly denying unknowns with the expectation that it would be stripped is in my opinion a bug, as local overrides should always have priority over options. I need to think about it a bit more before reverting (or not), but it really looks like you just got lucky that this bug was in your favor. |
Yeah, I agree. I think it ended up like that because (a few years back) I found that it was the only way to get I've adopted the new version in all our projects now, so all good from me. |
Hi there I think the stripUnknown is broken since this fix. I have gone through the commit and I think the tests are wrong.
I have added a few additional tests (see zip attached), they all fail now, but this is how I interprete the manual and parameters. kind regards Alexander |
Just sharing my 2 cents, but I'll leave it to the owners to keep me honest.
However, I tend to disagree on 3 and 4. Those objects explicitly allow extra properties to go through. The global option shouldn't affect those explicitly set flags. A use case I can think of: You want your schema to define I hope it makes sense. |
I agree with this, as I previously mentioned, local overrides should always have priority over options, and this is what happens here, but we can indeed add a root property to demonstrate that fully. |
Hi all I disagree, I do not understand the use of stripUnknown if it never strips unknown properties. Neither with unknown(true) or unknown(false). Am I missing something obvious here? kind regards Alexander |
It does when you don't give specific instructions for that schema, basically the default state. There is currently no way to go back to the default state but I think a |
Hi, all. I believe there is a misunderstanding going on here. And I am probably most confused of all. Would somebody try to set me right? Validation vs transformation@afharo says:
I think we all agree that this is a good use case. @Marsup ’s point that overrides should always have priority over options that have the same semantics is well taken too. However, I believe The point is that
would be weird, but
makes sense. TransformationWhen doing the following, the schema is not changed. @Alexander-Muylaert merely asks the transformation Joi does to strip the unknown properties.
A use case for this is as follows: suppose we are handling incoming JSON bodies in a service. Joi is used for validation and to sanitize the input (e.g., for security reasons). Joi's transformation functionality is used for the latter. There are ample other examples where we might want to do this. E.g., suppose we want to write the JSON body in a DynamoDB table we want to keep clean (no unknown properties), but we do not want to flag unknown properties as errors. Validation before transformation, or transformation before validation?From a security standpoint, we should validate first, and possibly transform after that. That is not what Joi does in all cases. It wouldn't make sense for
I would expect unknown properties to be stripped after validation, for example, using The same applies to Documentation
Note that
So whether unknown properties are allowed in I read this as, for the validation part:
(This is a bit weird to start with, because What is completely opaque to me now is what the effect of the following is supposed to be:
Is this correct? Probably not, because then Some comments above seem to mean that instead unknown keys are stripped in 1 case only, before validation?
In that light, I understand @Alexander-Muylaert ’s confusion. What I would expect, is indeed stripping after validation:
Alternative for @afharo ’s use case@afharo, in your use case, why would we ever activate |
IMO, there's a bit of confusion between
Based on my understanding of both settings as explained above, IMO, both of these are weird because they are contradictory (it doesn't matter if they are in the form of In that sense,
Yes... sorry that I didn't provide an actual code. The way to implement the use case is: const logEntry = {
message: "Error: Something went terribly wrong",
meta: {
trace_id: "12345",
extra_information: "https://www.youtube.com/watch?v=t3otBjVZzT0",
},
more_details: "...",
};
const loggerSchema = schema.object({
message: schema.string(),
meta: schema.object({
trace_id: schema.string(),
}).unknown(true),
});
const validLogEntry = loggerSchema.validate(logEntry, { stripUnknown: true });
// validLogEntry = {
// message: "Error: Something went terribly wrong",
// meta: {
// trace_id: "12345",
// extra_information: "https://www.youtube.com/watch?v=t3otBjVZzT0",
// },
// } You could also implement it as const logEntry = {
message: "Error: Something went terribly wrong",
meta: {
trace_id: "12345",
extra_information: "https://www.youtube.com/watch?v=t3otBjVZzT0",
},
more_details: "...",
error: {
message: "Something went terribly wrong",
code: "ETERRIBLYWRONG",
request: {
authentication: "Basic .....",
},
},
};
const loggerSchema = schema.object({
message: schema.string(),
meta: schema.object({
trace_id: schema.string(),
}).unknown(true),
error: schema.object({
message: schema.string(),
code: schema.string(),
}),
});
const validLogEntry = loggerSchema.validate(logEntry, { stripUnknown: true });
// OR
const loggerSchema = schema.object({
message: schema.string(),
meta: schema.object({
trace_id: schema.string(),
}).unknown(true),
error: schema.object({
message: schema.string(),
code: schema.string(),
}).strip(true),
}).strip(true);
const validLogEntry = loggerSchema.validate(logEntry);
// validLogEntry = {
// message: "Error: Something went terribly wrong",
// meta: {
// trace_id: "12345",
// extra_information: "https://www.youtube.com/watch?v=t3otBjVZzT0",
// },
// error: {
// message: "Something went terribly wrong",
// code: "ETERRIBLYWRONG",
// },
// } Again... it depends on your use case and code preferences/requirements to use it as a local option or global validate option. The global option avoids code repetition while the local ones are more explicit. In either case, you don't want |
When explicitly specifying
.unknown(false)
, running validations withstripUnknown: true
should respect the local override.