80

I am using the Joi validator for my HTTP requests. There I have a parameter called type. I need to make sure that the possible values for the parameter are either ios or android.

How can I do that?

body: {
  device_key : joi.string().required(),
  type : joi.string().required()
}
Mohammadreza Khedri
  • 2,523
  • 1
  • 11
  • 22
Eranga Kapukotuwa
  • 4,542
  • 5
  • 25
  • 30

6 Answers6

146

You can use valid.

const schema = Joi.object().keys({
  type: Joi.string().valid('ios', 'android'),
});

const myObj = { type: 'none' };
const result = Joi.validate(myObj, schema);
console.log(result);

This gives an error ValidationError: child "type" fails because ["type" must be one of [ios, android]]

AbhinavD
  • 6,892
  • 5
  • 30
  • 40
43

Maybe it will be useful for anyone who wants to check values based on existing enum/array of values.

const SomeEnumType = { TypeA: 'A', TypeB: 'B' };

Then just use this:

const schema = Joi.object().keys({
  type: Joi.string().valid(...Object.values(SomeEnumType)),
});

const myObj = { type: 'none' };
const result = Joi.validate(myObj, schema);
Max Podriezov
  • 958
  • 12
  • 14
  • 1
    This also works for Arrays. Very useful when you have, for example, an array of roles that you might want to validate against. Thanks @max-podriezov, it helped me with my case scenario. – arkanos Nov 15 '20 at 12:48
  • 2
    you don't need to spread the `Object.values()` since `valid()` takes an array. so remove the `...` – Fre Timmerman Jun 03 '21 at 09:38
  • 2
    On the latest version of Joi, `.valid()` no longer takes an array argument, so we need to spread the array using `...`. See: https://github.com/sideway/joi/issues/1449 – Audwin Oyong Dec 03 '21 at 00:33
  • I suggest you provide also enum syntax in your example code - I was convinced at first glance this is unprecise answer. – Eggon Sep 02 '22 at 09:48
  • as @Kariem showed in its answer, this also works with an actual `enum`, i.e. `enum SomeEnumType { TypeA: 'A', ... }` – netotz Oct 17 '22 at 18:57
  • This is wrong. `Object.values(SomeEnumType)` here is `['A', 'B', 0, 1]`. It should be `Object.values(SomeEnumType).filter((l) => isNaN(Number(l)))` instead to only allow `A` and `B` – AnonBird May 17 '23 at 16:16
6

For typescript, I think the most straightforward way is to just add the enum's values as valid values.

enum DeviceType {
    iOS = 'ios',
    Android = 'android',
}

Joi.string()
  // .allow(null) // uncomment this line to allow 'null'
  .valid(... Object.values(DeviceType))

This is essentially what jarora and Sinapcs suggested in previous answers without the separate function.

Kariem
  • 4,398
  • 3
  • 44
  • 73
  • 1
    +1 for demonstrating an actual `enum` and without an extra function. Sadly however this doesn't work for `const enum` :( – netotz Oct 17 '22 at 18:55
3

I am late for this answer. But following will helpful for others, who wants to use enum values with Joi String validation :

function validateBody(bodyPayload) {
    const schema = Joi.object({
        device_key : Joi.string().required(),
        type : Joi.string().valid('ios','android'),

    });
    return schema.validate(admin);
}

const bodyPayload = {device_key:"abc", type: "web"};
const result = validateBody(bodyPayload);

reference : https://hapi.dev/module/joi/api/#anyallowvalues

s4suryapal
  • 1,880
  • 1
  • 18
  • 26
3
function getEnumValues<T extends string | number>(e: any): T[] {
    return typeof e === 'object' ? Object.values(e) : [];
}

Joi.string().valid(...getEnumValues(YOUR_ENUM));
Sinapcs
  • 2,495
  • 1
  • 20
  • 23
  • 3
    Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Jan 30 '22 at 21:56
1

For typescript users,

getEnumValues<T extends string | number>(e: any): T[] {
        return typeof e === 'object' ? Object.keys(e).map(key => e[key]) : [];
}

Joi.string().valid(...getEnumValues(YOUR_ENUM));
jarora
  • 5,384
  • 2
  • 34
  • 46