fknop / hapi-pagination

Hapi plugin to handle "custom" pagination
MIT License
63 stars 36 forks source link

Not working correctly with Joi response validation #41

Closed garbles9100 closed 7 years ago

garbles9100 commented 7 years ago

I'm trying to apply Joi response validation to the pagination object generated by hapi-pagination using the following schema: response: { schema: { meta: { count: Joi.number().description('Number of observations in response.'), pageCount: Joi.number().description('Total number of pages.'), totalCount: Joi.number().description('Total number of observations.'), next: Joi.string().description('URL for the next page. Null if no next page.'), previous: Joi.string().description('URL for the previous page. Null if no previous page.'), self: Joi.string().description('URL for the current page.'), first: Joi.string().description('URL for the first page.'), last: Joi.string().description('URL for the last page.'), }, results: Joi.array(), }, },

And the response I get back in Postman is basically: { "meta": { "count": 2, "pageCount": 2, "totalCount": 5, "next": null, "previous": "XXX/?limit=3&page=1", "self": "XXX/?limit=3&page=2", "first": "XXX/?limit=3&page=1", "last": "XXX/?limit=3&page=2" }, "results": [] }

And yet I keep getting a Joi response validation error stating: "totalCount" is not allowed. "response" is not allowed.

From what I can tell, Joi thinks that the response it is checking the schema against contains a "response" key and "totalCount" key at the top level and yet in Postman I am not seeing a response like that at all.

Have you seen anything like this and is there any way to work around it?

garbles9100 commented 7 years ago

The "response" object in the Joi schema I posted is part of my endpoint:

server.route({ method: 'GET', path: '/', config: { validate: {}, response: { schema: { ... meta: { ... ....

fknop commented 7 years ago

Shouldn't the meta object be meta: Joi.object({}) instead ?

garbles9100 commented 7 years ago

It is automatically converted. This is from the Joi github page (https://github.com/hapijs/joi): "When passing a non-type schema object, the module converts it internally to an object() type ..."

That aside though, I had it as Joi.object() in my original code. I was just simplifying for posting here. I get the same issue when the schema is:

response: { schema: { meta: Joi.object({ count: Joi.number().description('Number of observations in response.'), pageCount: Joi.number().description('Total number of pages.'), totalCount: Joi.number().description('Total number of observations.'), next: Joi.string().description('URL for the next page. Null if no next page.'), previous: Joi.string().description('URL for the previous page. Null if no previous page.'), self: Joi.string().description('URL for the current page.'), first: Joi.string().description('URL for the first page.'), last: Joi.string().description('URL for the last page.'), }), results: Joi.array(), },

fknop commented 7 years ago

I believe the validation runs before the pre response handler. An object with totalCount and response is passed to the pre response handler. I don't think there is much I can do about that.

garbles9100 commented 7 years ago

Do people who use hapi-pagination just normally not do response validation? Because it seems like that would always be a problem.

fknop commented 7 years ago

I will check if I can move the logic of the pre-response before the validation run.

garbles9100 commented 7 years ago

Thank you, sir :)

fknop commented 7 years ago

@garbles9100 I moved the logic to a post handler and published to 1.16.0 on npm. Could you give it a try ? It shouldn't break anything as all the tests still pass.

garbles9100 commented 7 years ago

Yeah. That works great! Thanks!

garbles9100 commented 7 years ago

Hmm. Well I thought it was working. It doesn't appear to be applying validation at all now :/ I tried adding required objects that are not present in the response and Joi doesn't appear to be producing any error messages now.

fknop commented 7 years ago

Just read the Hapi doc for precisions, apparently, I need to do reply.continue(response) instead of reply(response).

As the docs says:

If the extension type is 'onPostHandler' or 'onPreResponse', a single argument passed to reply.continue() will override the current set response (including all headers) but will not stop the request lifecycle execution. To abort processing and return a response to the client, call reply(value) where value is an error or any other valid response.

fknop commented 7 years ago

Published 1.17.0

garbles9100 commented 7 years ago

Okay. Trying it now.

garbles9100 commented 7 years ago

Everything looks good now. No unexpected validation errors and validation for my current keys including the added pagination keys is working correctly. Thank you very much! This is a huge help!