58

I have a simple requirement. I tried to search on the internet as well as documentation but failed.
So here is what I want to achieve:

I have a schema:

const schema = Joi.object().keys({
  a: Joi.string().required(),
  b: Joi.string().required()
});

Now, How do I configure it such that any other key in the object would be allowed?

With this schema, it only allows two keys a and b. If I pass any other key, say, c, it throws an error saying that c is not allowed.

Anand Undavia
  • 3,493
  • 5
  • 19
  • 33
  • 7
    This question seems to get a lot of views so let me clarify this: I had accepted the answer by Carsten because at the time, it was the solution which worked for me and my question was answered in less than an hour. But it might not be best solution for you. Just scroll down and check out the highest upvoted answer by Niels. As clean as the answer is, I would however not mark it as accepted as it would be mortifying the efforts put by Carsten. – Anand Undavia Jun 27 '19 at 06:06

2 Answers2

183

The correct answer is actually to use object.unknown(true).

const schema = Joi.object().keys({
  a: Joi.string().required(),
  b: Joi.string().required()
}).unknown(true);
Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136
  • 4
    Simple and straight answer, nice +1 :) – Ankur Verma Feb 06 '19 at 05:35
  • 4
    this should be the best answer. – MH. Abdi Jul 21 '19 at 10:40
  • 7
    `true` param is not required since it is the default. Use only `.unkown()` for the same effect. – Patrik Fuhrmann Oct 12 '19 at 23:48
  • 1
    I recommend clarity over brevity when writing validation schemes. Yes, the parameter is not required because default, but explicitly providing it prevents any possible confusion as to the intent. – Niels Keurentjes Nov 27 '19 at 14:45
  • 3
    The selected answer is actually not a bad answer. Unknown true will allow unknown keys, sure. It will not, however, allow you to specify what type your unknowns should be. The 'right' answer would force all unknowns to be of a string type. This is perfectly useful in some situations. – HailZeon May 19 '20 at 08:19
  • @HailZeon that was not the question however. `.unknown` is the correct answers to the question ("how do I allow any other key in the object"), clearer and much faster than applying a regex to every key. – Niels Keurentjes Jun 02 '20 at 07:50
  • still valid answer. – utkuDAT Dec 09 '22 at 23:23
12

You can add unknown keys using object.pattern(regex, schema) this way IF you want to make sure these unknown keys are strings:

const schema = Joi.object().keys({
  a: Joi.string().required(),
  b: Joi.string().required()
}).pattern(/./, Joi.string());

For a general pass of all key types use object.unknown(true):

const schema = Joi.object().keys({
  a: Joi.string().required(),
  b: Joi.string().required()
}).unknown(true);
Carsten
  • 848
  • 1
  • 6
  • 14
  • 1
    using `.pattern(/./, Joi.any())` did it. ( because there can be nested objects as well ). Thanks! – Anand Undavia Apr 18 '18 at 15:13
  • 2
    https://github.com/hapijs/joi/blob/master/API.md#objectunknownallow might be easier – Shawn C. Apr 19 '18 at 12:49
  • 1
    Would be better to mark the answer from @Niels Keurentjes as the accepted answer. This might work, but should not be promoted as the goto solution. – mraxus May 17 '19 at 14:30
  • 3
    Again, this is a MORE SPECIFIC version of allow unknown. This code is allowing the user to specify that all unknown keys MUST be a string. This is very useful in some situations like creating a REST API filter where all unknown filter parameters must conform to a given schema. – HailZeon May 19 '20 at 08:24
  • 2
    I agree, there is no reason to downvote this solution. The `unknown(true)` option will allow anything, but if you want to only allow specific keys, the regex pattern is your friend. – Adam Reis Nov 27 '20 at 01:08
  • 1
    I’m glad this remained the accepted answer because I might have scanned past it otherwise (given the mysterious negative votes). This does what I came here looking for, unlike the other. However it’s worth noting that /./ doesn’t match all string property names. Specifically it doesn’t match the empty string. There are a lot of ways to write "match anything," but /^/ for example would do the trick (every string, even the empty string, begins). – Semicolon Jan 17 '21 at 10:58