Skip to content
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

Validate array of objects? #67

Closed
gh-naylor opened this issue Dec 27, 2013 · 17 comments
Closed

Validate array of objects? #67

gh-naylor opened this issue Dec 27, 2013 · 17 comments

Comments

@gh-naylor
Copy link

When I submit a single object as my payload I can validate keys very easily with:

req.checkBody('year', 'invalid year').len(4,4).isNumeric();

But I would like to submit an array of objects and loop through them with something like:

_.each(self.req.body, function(element, index, list) {
    req.checkBody([index].year, 'invalid year').len(4,4).isNumeric();
});

I've also tried using req.assert with element.year and even element.year.toString() with no luck.

What am I doing wrong? Or is this type of functionality even possible?

@Mirodil
Copy link

Mirodil commented Jan 16, 2014

I have the same problem with items of array

@rustybailey
Copy link
Collaborator

Related issue here: #125. There is a solution offered in that issue. Please continue the conversation there.

@jyotman
Copy link
Contributor

jyotman commented Feb 17, 2017

@rustybailey @gustavohenke @IOAyman I don't think this is same issue as #125.

I think the OP was asking what if the req.body is an array of objects itself.

Example JSON -

[
    {"name": "Abc"},
    {"name": "Def"}
]

How do I begin to validate this. What argument do I provide to req.checkbody() because I want to validate the body itself. I want to do something like req.checkBody().isArray().

@base698
Copy link

base698 commented Nov 11, 2017

          body('pages')
             .custom((item)=>_.isArray(item) && item.length > 0)
             .withMessage( "At least one page is required")

What about this?

@foodaka
Copy link

foodaka commented May 17, 2018

@jyotman did u find a workaround for this ? is there a way to validate the objects in the array iteself? pretend the post payload looks something like below. how to validate name is string and age is int in the array.

[
 { name: 'joe', age: 25},
 {name: 'alice', age: 30}
]

@gustavohenke
Copy link
Member

@foodaka please have a look at Wildcards

@jyotman
Copy link
Contributor

jyotman commented May 20, 2018

@foodaka I did something like this -

for(let i = 0; i < req.body.length; i++)  {
    req.checkBody([i, 'name']).notEmpty();
    req.checkBody([i, 'age']).isInt();
}

@ealexhaywood
Copy link

ealexhaywood commented Aug 6, 2018

I was able to do it with wildcards like this:

/* Raw alerts fired from Prometheus Server */
app.post('/api/v1/alerts', [
  body().isArray(),
  body('*.labels', 'labels field must be a JSON object').exists().isJSON(),
  body('*.annotations', 'annotations field must a JSON object').exists().isJSON(),
  body('*.startsAt', 'startsAt field must be a string').exists().isString(),
  body('*.endsAt', 'endsAt field must be a string').exists().isString(),
  body('*.generatorURL', 'generatorURL field must be a URL').exists().isURL({ require_tld: false })
], (req, res) => {
  // Finds the validation errors in this request and wraps them in an object with handy functions
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(422).json({ errors: errors.array() });
  }

  alerts = req.body;
  return res.status(200).json(alerts);
});

where my req.body is:

[{
    "labels": {
      "alertname": "IOWarning",
      "device": "sda",
      "instance": "localhost:9100",
      "job": "node",
      "severity": "warning"
    },
    "annotations": {
      "description": "I/O Usage Read/Write: This is dangerous and rectified immediately",
      "summary": "I/O Usage Read/Write Alert"
    },
    "startsAt": "2018-08-06T17:16:54.26404133Z",
    "endsAt": "0001-01-01T00:00:00Z",
    "generatorURL": "http://prometheus-server:9090/graph?g0.expr=irate%28node_disk_written_bytes_total%5B1m%5D%29+%3E+0&g0.tab=1"
}]

@gofurnazarov
Copy link

I used Wildcards in this situation and worked well.

array_of_objects:

[
  { name: 'something', value: 'anything'},
  { name: 'something', value: 'anything'},
  { name: 'something', value: 'anything'}
]

Validate array items:
check('array_of_objects[*].*').trim().isLength({ min: 1, max: 10 }) etc.

@BertCatsburg
Copy link

For me the custom validation of express-validator was the simplest.

check('myArray')
   .isArray()
   .custom ( a => {
       // a holds the full array
       return a.every( (e) => {
         // e is each element in the array
         if (e === "ok") {
            return true;
         } else {
            return false;
             // if you return false at least once, then the result of 'every' is false and 
             // the validator triggers an error
         }
      }
    .withMessage('Array must contains strings with the word "ok" ')

@ddemydenko
Copy link

So how can I validate array of instance based on schema?
I am looking for something like this:

checkSchema(schema, myArray);

Now I have not such possibility, cause checkSchema uses req.body, and when body is
[
{ name: 'something', value: 'anything'},
{ name: 'something', value: 'anything'},
{ name: 'something', value: 'anything'}
]
It doesn't work properly

@BertCatsburg
Copy link

Hello @ddemydenko,
I don't understand your question. According to the docs the checkSchema accepts 1 object with fields as keys with each an object (containing the validations) as values. Each value seems to have an 'options' which has 'req' available. (Although I haven't worked it myself, I'm more than happy to play around it for you)
Your example shows 2 params to checkSchema. That I don't understand.

@ddemydenko
Copy link

Hello @ddemydenko,
I don't understand your question. According to the docs the checkSchema accepts 1 object with fields as keys with each an object (containing the validations) as values. Each value seems to have an 'options' which has 'req' available. (Although I haven't worked it myself, I'm more than happy to play around it for you)
Your example shows 2 params to checkSchema. That I don't understand.

I have a post method, that according to restfull api can accepts one instance or array of the same instances. So I looking for a possibility using this approach Schema Validation to bulk create :

POST /plots/ HTTP/1.1
Host: localhost:5000
[
  { name: 'something', value: 'anything'},
  { name: 'something', value: 'anything'},
  { name: 'something', value: 'anything'}
]

I already have a schema, that works fine for one instance but I want apply it for many instances. How I can iterate array?

@BertCatsburg
Copy link

Regardless of the checkSchema, I've put your request in my 'check' example.
Is this what you require?

check('myField')
    .custom(a => {
        if (Array.isArray(myField)) {
            return a.every((e) => e.name === "something" && e.value === "anything")
        }
        return (a.name === "something" && a.value === "anything")
    })
    .withMessage('Either and Array or an Instance please');

@ddemydenko
Copy link

ddemydenko commented Jan 24, 2019

Here is my server:

const express = require('express');
const expressValidator = require('express-validator');
const { checkSchema } =  require('express-validator/check');

const app = express();
const port = 3000;
const schema = require('./schema.json');

app.use(express.json());
app.use(expressValidator());
app.post('/users',checkSchema(schema), (req, res) => {
    const err = req.validationErrors();
    console.log(err);
    res.send(err)
});

app.listen(port);

Here is my schema.json

{
  "guid": {
    "isEmpty": false
  },
  "url": {
    "isEmpty": false,
    "isURL": true
  },
  "amount": {
    "isEmpty": false,
    "isFloat": true
  }
}

And here is my single object request, validates as expected

POST /plots/ HTTP/1.1
Host: localhost:5000
{
    "url": "https://www.example.com/plots/7uJ3g62fqHhax3dLzmZGGn",
    "type": "Field",
    "amount": 25
}

Since I already have a defined schema, therefor to avoid code duplication I want to use this schema to validate multi objects creation, aka bulkCreate

POST /plots/ HTTP/1.1
Host: localhost:5000
[
    {
        "url": "https://www.example.com/plots/7uJ3g62fqHhax3dLzmZGGn",
        "type": "Field",
        "amount": 25
    },
    {
        "url": "https://www.example.com/plots/7uJ3g62fqHhax3dLzmZGGn",
        "type": "Field",
        "amount": 25
    }
]

But this case works wrong. Validation failed, Because checkSchema consider body like a single object.
I am looking for a way to iterate array, or something else that allows me validate single object and array of object as well.

@ddemydenko
Copy link

Ok, folks, it is very unobvious, and this trick undocumented. I had to add asterisk
Here is solution

{
  "*.guid": {
    "isEmpty": false
  },
  "*.url": {
    "isEmpty": false,
    "isURL": true
  },
  "*.amount": {
    "isEmpty": false,
    "isFloat": true
  }
}

@gustavohenke
Copy link
Member

gustavohenke commented Feb 17, 2019

it is very unobvious, and this trick undocumented. I had to add asterisk

@ddemydenko it's documented under wildcards.


I'm locking the conversation since this is a 5 years old issue which has had a solution for a while now.
If you still have trouble using wildcards, please open a new issue. Thanks.

@express-validator express-validator locked as resolved and limited conversation to collaborators Feb 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests