最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - How can we write a Joi schema for different request types? - Stack Overflow

matteradmin4PV0评论

I've been trying to create a schema. It represents my object, which is like {name:"Joe Doe", id:"1234567890"} But on the first request which is for creating new one; it should not have an id parameter in the object. Otherwise it might be meaning an update to consumer...

Would you have any idea about the best way to implement it?

What I need as a joi schema;

joi.object().keys({
    id: joi.string().forbidden() or required(),
    name: joi.string(),
    ...

Sample requests;

Create:

POST Request... 'api/v1/item/'

Object : {name:"Joe Doe"}

Update:

PUT Request... 'api/v1/item/'

Object : {id:"1234567890", name:"Joe Doe"}

I've been trying to create a schema. It represents my object, which is like {name:"Joe Doe", id:"1234567890"} But on the first request which is for creating new one; it should not have an id parameter in the object. Otherwise it might be meaning an update to consumer...

Would you have any idea about the best way to implement it?

What I need as a joi schema;

joi.object().keys({
    id: joi.string().forbidden() or required(),
    name: joi.string(),
    ...

Sample requests;

Create:

POST Request... 'api/v1/item/'

Object : {name:"Joe Doe"}

Update:

PUT Request... 'api/v1/item/'

Object : {id:"1234567890", name:"Joe Doe"}

Share Improve this question edited Dec 30, 2019 at 15:43 atasoyh asked Dec 30, 2019 at 15:38 atasoyhatasoyh 3,1456 gold badges34 silver badges59 bronze badges 3
  • can you add request and payload example with the question please? – Ashish Modi Commented Dec 30, 2019 at 15:41
  • @AshishModi I've added them. – atasoyh Commented Dec 30, 2019 at 15:47
  • added the answer. hope it helps. – Ashish Modi Commented Dec 30, 2019 at 16:07
Add a ment  | 

4 Answers 4

Reset to default 6

You can use Joi's context option while calling validate method. something like

var Joi = require("@hapi/joi");

const schema = Joi.when(Joi.ref("$method"), {
          "is": "put",
          "then": Joi.object().keys({
            "id": Joi.string().required(),
            "name": Joi.string()
          }),
          "otherwise": Joi.object().keys({
            "id": Joi.string().forbidden(),
            "name": Joi.string()
          })
        });

function validate() {
    const result = schema.validate({"id": "123", "name": "myname"}, {"context": {"method": "put"}});
    console.log(result);
}

validate();

if you pass method as put, it will use put schema else post schema.

On the project, we still use 14.3.1 version of joi. I could solve my problem with creating a base joi object and extending it like;

const base = joi.object().keys({name: joi.string()});
const put = base.keys({
    id: joi.string().required(),
});
const post = base.keys({
    id: joi.string().forbidden(),
});

Even it looks cleaner to read. I leave that here for if someone needs something similar.

I have the same use case on my app, what I've done is adding a flag on the Joi context

const conditionalIdValue = Joi.any().when('$isEditForm', {
  is: Joi.boolean()
    .valid(true)
    .required(),
  then: Joi.string()
    .required(),
  otherwise: Joi.forbidden(),
});

const schema = joi.object().keys({
  id: conditionalIdValue,
  name: joi.string(),
  ...
});

where I'm calling Joi.validate I have an access to the request it self, so you can attach isEditForm with the proper value on the context.

// validation middleware

export const validationMiddleWare = async (req, res, next) => {
  try {
    req.body = await Joi.validate(req.body, schema, {
      context: { isEditForm: req.method === 'POST' },
    });
    return next();
  } catch (e) {
    // reject the request
  }
};

const Joi = require("joi");

const schema = Joi.object().keys({
   //General attributes that will be required in all put/post request
  noOfCopies: Joi.number().required(),
});

const put = schema.keys({
    customerId: Joi.string().required().forbidden(),
    movieId: Joi.string().required().forbidden(),
});

const post = schema.keys({
  customerId: Joi.string().required(),
  movieId: Joi.string().required(),
});

function validator(payload,method) {
  
  const validationMethod = (method === "POST" ) ? post : put ;
  const { error } = validationMethod.validate(payload);

  return error;
}

module.exports = validator;


//In Your Controller
validator(req.body,req.method)

Post a comment

comment list (0)

  1. No comments so far