How to validate array of objects using Joi?

I am getting an array of objects to backend, where each object contains a service name. The structure looks like below

[{"serviceName":"service1"}, {"serviceName":"service2"},..] 

when I get the array at backend, I want to validate that every object in the array has serviceName property.

I had written the following code, but even though I pass valid array, I am getting validation error.

var Joi = require('joi'); var service = Joi.object().keys({ serviceName: Joi.string().required() }); var services = Joi.array().ordered(service); var test = Joi.validate([{serviceName:'service1'},{serviceName:'service2'}],services) 

For the above code, I am always getting the validation error with message

"value" at position 1 fails because array must contain at most 1 items 

6 Answers

replacing ordered with items will work.

let Joi = require('joi') let service = Joi.object().keys({ serviceName: Joi.string().required(), }) let services = Joi.array().items(service) let test = Joi.validate( [{ serviceName: 'service1' }, { serviceName: 'service2' }], services, ) 

For reference click here

4

A basic/ clearer example is as follows. To validate a JSON request like this:

 { "data": [ { "keyword":"test", "country_code":"de", "language":"de", "depth":1 } ] } 

Here is the Joi validation:

 seoPostBody: { body: { data: Joi.array() .items({ keyword: Joi.string() .required(), country_code: Joi.string() .required(), language: Joi.string() .required(), depth: Joi.number() .required(), }), }, }; 

This is what I am doing in NodeJs, might need some slight changes for other platforms

1
const test = { body: Joi.array() .items({ x: Joi.string().required(), y: Joi.string().required(), z: Joi.string().required(), date: Joi.string().required(), }) }; 
1

Just want to make it more clear. I'm currently using "@hapi/joi:16.1.7".

Let's say you want your schema to validate this array of objects.

const example = [ { "foo": "bar", "num": 1, "is_active": true, } ]; 

Then schema's rules should be:

var validator = require('@hapi/joi'); const rules = validator.array().items( validator.object( foo: validator.string().required(), num: validator.number().required(), is_active: validator.boolean().required(), ), ); const { error } = rules.validate(example); 

For Joi you can use below which is working fine for me, this will validate that array must have at-least on object with key serviceName-

const Joi = require('joi'); const itemsArray = Joi.array().items( Joi.object({ serviceName: Joi.string().required(), }) ).min(1).required(); const itemSchema = Joi.array().items(itemsArray).when('checkout_type', { is: 'guest', then: Joi.array().required(), }).required(); let schema = Joi.object().keys({ items: Joi.alternatives().try(itemsArray, itemSchema).required(), }); 
1

Libraries like these are great but wouldn’t it be even better if we could use them in a more seamless way, like in a Request pipeline? Let’s have a look firstly how we would use Joi in an Express app in Node.js:

const Joi = require('joi'); app.post('/blog', async (req, res, next) => { const { body } = req; const blogSchema = Joi.object().keys({ title: Joi.string().required description: Joi.string().required(), authorId: Joi.number().required() }); const result = Joi.validate(body, blogShema); const { value, error } = result; const valid = error == null; if (!valid) { res.status(422).json({ message: 'Invalid request', data: body }) } else { const createdPost = await api.createPost(data); res.json({ message: 'Resource created', data: createdPost }) } }); 

The above works. But we have to, for each route:

  1. create a schema
  2. call validate()

It’s, for lack of better word, lacking in elegance. We want something slick looking

Building a middleware

Let’s see if we can’t rebuild it a bit to a middleware. Middlewares in Express is simply something we can stick into the request pipeline whenever we need it. In our case we would want to try and verify our request and early on determine whether it is worth proceeding with it or abort it.

So let’s look at a middleware. It’s just a function right:

const handler = (req, res, next) = { // handle our request } const middleware = (req, res, next) => { // to be defined } app.post( '/blog', middleware, handler ) 

It would be neat if we could provide a schema to our middleware so all we had to do in the middleware function was something like this:

(req, res, next) => { const result = Joi.validate(schema, data) } 

We could create a module with a factory function and module for all our schemas. Let’s have a look at our factory function module first:

const Joi = require('joi'); const middleware = (schema, property) => { return (req, res, next) => { const { error } = Joi.validate(req.body, schema); const valid = error == null; if (valid) { next(); } else { const { details } = error; const message = details.map(i => i.message).join(','); console.log("error", message); res.status(422).json({ error: message }) } } } module.exports = middleware; 

Let’s thereafter create a module for all our schemas, like so:

// schemas.js const Joi = require('joi') const schemas = { blogPOST: Joi.object().keys({ title: Joi.string().required description: Joi.string().required() }) // define all the other schemas below }; module.exports = schemas; 

Ok then, let’s head back to our application file:

// app.js const express = require('express') const cors = require('cors'); const app = express() const port = 3000 const schemas = require('./schemas'); const middleware = require('./middleware'); var bodyParser = require("body-parser"); app.use(cors()); app.use(bodyParser.json()); app.get('/', (req, res) => res.send('Hello World!')) app.post('/blog', middleware(schemas.blogPOST) , (req, res) => { console.log('/update'); res.json(req.body); }); app.listen(port, () => console.log(`Example app listening on port ${port}!`)) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like