Badr
Badr

Reputation: 10648

Validating JSON query string as query param using Joi

I have a problem of validation JSON that is passed in GET request query param as a serialized string.

What I need to achieve is to parse this serialized string back to JSON and validated it using Joi.

Example: Give is the JSON

{
 limit: {size:10, page:0},
 filter: {filter_by: 'foo', filter_val: 'foo', from: '1/1/2016',to: '1/1/2016' }
}

And this JSON is converted to query string is:

limit%5Bsize%5D=10&limit%5Bpage%5D=0&filter%5Bfilter_by%5D=foo&filter%5Bfilter_val%5D=foo&filter%5Bfrom%5D=1%2F1%2F2016&filter%5Bto%5D=1%2F1%2F2016

I need something like this to check:

 validate: {
          query: {
            limit: Joi.someMethodToGetJsonFromString.object().keys({
              size: Joi.number(),
              page: Joi.number()
            }
          filter: Joi.someMethodToGetJsonFromString,.object().keys({
              filter_by: Joi.string().valid(['option1', 'option2']),
              filter_val: Joi.string(),
              from: Joi.date(),
              to: Joi.date(),
            }
        }

Is there anything in Joi that can help in this scenario, Or I need to write custom validation functions for it.

Upvotes: 5

Views: 6429

Answers (1)

Matt Harrison
Matt Harrison

Reputation: 13567

You'll want to swap out the query string parsing used because hapi doesn't support that format by default. It just uses Node's built in url module to parse the URL which doesn't support complex encodings of query strings. You'll need to manually parse it using qs, after that you can validate as normal.

Hapi Version ≥18

You can set your custom parser via server.options.query.parser.

Hapi Version ≤17

const Hapi = require('hapi');
const Joi = require('joi');
const Url = require('url');
const Qs = require('qs');

const server = new Hapi.Server();
server.connection({ port: 4000 });

const onRequest = function (request, reply) {

    const uri = request.raw.req.url;
    const parsed = Url.parse(uri, false);   // skip the querystring parsing
    parsed.query = Qs.parse(parsed.query);  // parse it ourselves with qs
    request.setUrl(parsed);

    return reply.continue();
};

server.ext('onRequest', onRequest);

server.route({
    config: {
        validate: {
            query: {
                limit: Joi.object().keys({
                    size: Joi.number(),
                    page: Joi.number()
                }),
                filter: Joi.object().keys({
                    filter_by: Joi.string().valid(['option1', 'option2']),
                    filter_val: Joi.string(),
                    from: Joi.date(),
                    to: Joi.date(),
                })
            }
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        return reply('ok');
    }
});

server.start((err) => {

    if (err) {
        throw err;
    }
    console.log('Started server');
});

This is discussed a little bit in the API docs under the request.setUrl() method.

Upvotes: 4

Related Questions