Hapi: POST with empty payload fails validation (with Joi)

Created on 17 Aug 2015  路  6Comments  路  Source: hapijs/hapi

I have a route with an optional payload. After upgrading to v9, the route returns 400 when the payload is missing. I assume this is because an empty payload is now transformed to null instead of {}, and when null is passed to Joi, Joi responds with "value" must be an object.

To reproduce:

var Hapi = require('hapi');
var Joi = require('joi');

// Create a server with a host and port
var server = new Hapi.Server();
server.connection({
    host: 'localhost',
    port: 8000
});

// Add the route
server.route({
    method: 'POST',
    path: '/hello',
    config: {
        validate: {
            payload: {
                name: Joi.string()
            }
        },
        handler: function (request, reply) {
           reply('hello ' + (request.payload.name || 'world'));
        }
    },
});

// Start the server
server.start(function() {
     console.log('Server running at:', server.info.uri);
});

My use case is an action for resetting a password, where users are allowed to provide a password in the payload, but if a password is not provided, we generate one automatically.

documentation non issue

Most helpful comment

It is possible that this is not a bug, but simply a consequence of the updated payload parsing. At least I managed to find a work around:

server.route({
    method: 'POST',
    path: '/hello',
    config: {
        validate: {
            payload: Joi.object({
                name: Joi.string()
            }).allow(null)
        },
        handler: function (request, reply) {
           reply('hello ' + ((request.payload || {}).name || 'world'));
        }
    }
});

All 6 comments

This definitely looks like a bug. Essentially, the value null is suppied to Joi.validate() when a POST request is empty and contains no content-type header.

The same happens if content-type is set to text/plain or application/json, or if it's not set at all.

It is possible that this is not a bug, but simply a consequence of the updated payload parsing. At least I managed to find a work around:

server.route({
    method: 'POST',
    path: '/hello',
    config: {
        validate: {
            payload: Joi.object({
                name: Joi.string()
            }).allow(null)
        },
        handler: function (request, reply) {
           reply('hello ' + ((request.payload || {}).name || 'world'));
        }
    }
});

allow(null) works for me. I had to change how I check for empty payload, but that's ok.

@hueniverse perhaps this can be resolved by noting in the "Empty Payload" section of the 9.0.0 migration checklist (#2682) how to field empty request payloads (that are allowed to be empty) when using Joi validation. The pattern is to use Joi.object(/* ... */).allow(null).

Related to #2576 ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hueniverse picture hueniverse  路  4Comments

leore picture leore  路  3Comments

taoeffect picture taoeffect  路  3Comments

DrMabuse23 picture DrMabuse23  路  5Comments

midknight41 picture midknight41  路  4Comments