mac- / ratify Goto Github PK
View Code? Open in Web Editor NEWA Hapi plugin for validating the schema of path, query, request body, and response body params using JSON-schema
License: MIT License
A Hapi plugin for validating the schema of path, query, request body, and response body params using JSON-schema
License: MIT License
Hi,
I'm not sure if this is an issue with ratify or something else, but when I try to generate code with swagger-js-codegen and pointing to the root documentation generated by ratify it generate an error (TypeError: Cannot read property 'forEach' of undefined
)
But if I point to a specific route in the doc the generation works fine, but this would mean I need to generate seperatly each routes witch is not what I want.
This is what I have when pointing to the api-docs:
{ apiVersion: '0.1.0', swaggerVersion: '1.2', apis: [ { path: '/api/1.0.0/users' }, { path: '/api/1.0.0/connexion/checkAndDecodeSession' }, { path: '/api/1.0.0/connexion/login' }, { path: '/api/1.0.0/connexion/logout' } ] }
At least if /api/1.0.0/connexion/* could all be grouped into a single end point /api/1.0.0/connexion. Maybe I'm doing something wrong because I don't understand why they are generated a separated routes. According to my understanding checkAndDecodeSession, login and logout should be methods of connexion endpoint and not individual endpoints. Is there any way to help ratify to defined the correct endpoint ?
Thanks for your help.
I believe schemas like this one should be usable:
response: {
schema: {
// response payload schema
type: 'string'
},
sample: 100, // percentage of responses to test against the schema
failAction: 'log' // action to take when schena validation fails. Valid options are; 'log' and 'error'
}
IMO it should be up to the schema whether something is a valid response or not. Thoughts?
https://github.com/mac-/ratify/blob/master/lib/RouteSchemaManager.js#L267-L269
Right now the following code is being used to report errors:
https://github.com/mac-/ratify/blob/master/lib/RequestValidator.js#L28-L29
A recent minor change in z-schema zaggino/z-schema#53 provides additional information for failed string patterns (regex) through the error.description
property.
It would be very useful if that property was available in the error message. For example:
errorMessages = 'path parameters validation error: ' +
_.map(report.errors, function(error) {
var message = error.message;
if (error.description){
message += '. Details: ' + error.description
}
return message;
}).join(', ');
Hi,
I'm trying to use this plugin but I'm new to hapi, nodejs, and json-schema.
I have created 2 files, one describe an element, and the other an array of the first element. I'm trying to use the $ref property but without success.
I'm not sure of what I should put in it. By default I should specify the id of the first element, but as it's not in the same file it's not defined. As the files are not online yet I can't use a fixed url either. So I tried with relative path (./element.json) or with "file://" syntax but with no success yet. Maybe I'm not is the good working directory.
Could someone tell me if such a think is possible with ratify, and how to achieve this ?
Thanks.
Upgrade to latest version (3.x.x).
Some ramifications:
Core node module querystring
was updated in Node v6 to return plain objects that do not prototypically extend from the JavaScript Object
.
According to the Node docs:
This means that the typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.
See Node.js PR here:
nodejs/node#6055
breaking changes list for v5-v6:
https://github.com/nodejs/node/wiki/Breaking-changes-between-v5-and-v6#querystring
As a result of this change, this packages validation of parsed query strings throws an error on this line when the var object
is a parsed query string:
https://github.com/mac-/ratify/blob/master/lib/RouteSchemaManager.js#L117
For example:
"prop": {
"type": "boolean",
"description": "true if the user's metadata properties must be included in the returned user, false otherwise.",
}
And validation fails for:
return request.getAsync({
url: BASE_URL,
json: true,
qs: {
include_metadata: false
}
})
Because false
is converted to 'false'
when the qs is parsed.
When trying to register the plugin using the following code:
var ratifyOptions = {
apiVersion: 'v2',
startingPath: '/api'
};
server.pack.register({ plugin: require('ratify') }, ratifyOptions, function(err) {
if (err) {
console.log('error', 'Failed loading plugin: ratify');
}
});
I get the following error message (removed beginning of paths):
hapi/node_modules/hapi/node_modules/hoek/lib/index.js:425
throw new Error(msgs.join(' ') || 'Unknown error');
^
Error: Invalid register options {
"startingPath" [1]: "/api",
"apiVersion" [2]: "v2"
}
[1] apiVersion is not allowed
[2] startingPath is not allowed
at Object.exports.assert (/node_modules/hapi/node_modules/hoek/lib/index.js:425:11)
at Object.exports.assert (/node_modules/hapi/lib/schema.js:15:10)
at internals.Pack._plugin (/node_modules/hapi/lib/pack.js:271:12)
at hapi/node_modules/hapi/lib/pack.js:260:14
at iterate (/node_modules/hapi/node_modules/items/lib/index.js:35:13)
at Object.exports.serial (/node_modules/hapi/node_modules/items/lib/index.js:38:9)
at internals.Pack._register (/node_modules/hapi/lib/pack.js:258:11)
at internals.Pack.register (/node_modules/hapi/lib/pack.js:179:17)
at Object.<anonymous> (index.js:37:13)
at Module._compile (module.js:456:26)
The validation that seems to be failing is this one.
Is that the correct way to provide the options?
The cause is https://github.com/mac-/ratify/blob/master/lib/RouteSchemaManager.js#L242.
Basically if (request.raw.req.headers['content-type'].indexOf('application/x-www-form-urlencoded') === 0)
should handle the case where request.raw.req.headers['content-type']
is undefined.
Error messages on failed types do not include property name.
Currently, the following validation:
ratify: {
payload: {
type: "object",
properties: {
outer: {
type: "object",
properties: {
inner:{
type: "string"
}
}
}
}
}
}
Together with this payload:
{
"outer": {
"inner": false
}
}
Results in this response:
{
"statusCode": 400,
"error": "Bad Request",
"message": "payload parameters validation error: invalid type: boolean (expected string)"
}
The available information when creating the error message is:
{ code: 'INVALID_TYPE',
message: 'invalid type: boolean (expected string)',
path: '#/outer/inner',
params: { expected: 'string', type: 'boolean' } }
The current code looks like this:
if (!report.valid) {
errorMessages = 'payload parameters validation error: ' +
_.map(report.errors, function(error) { console.log(error); return error.message; }).join(', ');
return next(plugin.hapi.error.badRequest(errorMessages));
}
If it were updated to something like this it would provide more detailed error messages:
if (!report.valid) {
errorMessages = 'payload parameters validation error: ' +
_.map(report.errors, function(error) {
var message = error.message;
message += ' - on ';
// handle array case
message += error.path.substr(2).replace(/\//g, ".").replace(/\.\[/g, "[")
return message;
}).join(', ');
Seems to be ~2x as fast as z-schema http://gilesbowkett.blogspot.co.uk/2015/01/why-panda-strike-wrote-fastest-json.html.
Might be worth exploring since this is something that is executed on every request.
Thoughts?
This is the function code:
findPackageJson = function(startingDirectory) {
if (!startingDirectory) {
return false;
}
if (fs.existsSync(startingDirectory + '/package.json')) {
return startingDirectory + '/package.json';
}
console.log(startingDirectory);
return findPackageJson(startingDirectory.replace(/\/[^\/]+?$/g, ''));
},
In my example, the startingDirectory
is cli.js
.
fs.existsSync(startingDirectory + '/package.json')
is false, and then startingDirectory.replace(/\/[^\/]+?$/g, '')
is cli.js
again.
It looks like hapi is using the qs
module which should parse arrays in query strings properly. Look into removing the convertArraysInQueryString
method in RouteSchemaManager.js
Pretty useful if you want to hide some things that are available but don't want documented yet. Also having a function allows you to decide if you want it displayed in a local env but not prod.
Would require changing: https://github.com/mac-/ratify/blob/master/lib/SwaggerManager.js#L313 with a filter
before the forEach
.
I see it's already here: https://github.com/mac-/ratify/blob/master/lib/SwaggerManager.js#L13-L18 but does not allow runtime checks.
More useful information about the error could be provided.
Hi @mac-, would you accept a PR to automatically convert strings defined with date-time
formats to Date
object? This is useful, for example, when saving Date
objects to MongoDB - otherwise they are persisted as strings by default.
Current behavior is here:
ratify/lib/RouteSchemaManager.js
Line 107 in 9f3b09d
Seems this would be a breaking change. The only other JSON schema string format that has an equivalent Node type is uri
, which we might want to convert automatically as well. Let me know what you think.
Thanks!
Hi,
First of all thanks for this great plugin. I'm just starting to use it and it seems very great.
I have a simple question please, is it possible to set the sample rate for response validation globaly ?
The main reason is that in 90% case I want a 100% validation in test/dev but lower in production. This setting is usally global so it would be great to set it in one single place. This would reduce the code as I won't have to set it on every path but only when I want a specific sample rate (for some critics route maybe).
The same option would be great for failAction.
Thanks a lot.
It reads:
var ratifyOptions = {};
server.pack.register({ plugin: require('ratify') }, ratifyOptions, function(err) {
if (err) {
console.log('error', 'Failed loading plugin: ratify');
}
});
It should be:
var ratifyOptions = {};
server.pack.register({ plugin: require('ratify'), options: ratifyOptions }, function(err) {
if (err) {
console.log('error', 'Failed loading plugin: ratify');
}
});
I've been exploring a few different options for automatic schema validation and API documentation. I noticed both lout and hapi-swagger support the following configuration for routes:
server.route({
method: "GET",
path: "/something/{somethingId}",
config: {
description: "Get's a something",
tags: ["api"],
validate: {
params: {
somethingId: Joi.string()
},
headers: Joi.object({
"authorization": Joi.string().required()
}).options({ allowUnknown: true })
},
response: {
schema: Joi.object({
})
}
},
handler: function (request, reply) {
// ...
}
});
But ratify seems to require a different type of configuration structure with everything under a plugins and then a ratify object.
Is there a reason for the different structure? Would it be possible to re-use the same structure that others use that don't specify the ratify plugin explicitly? I mostly just want an easy way to keep things consistent but have the option of changing out documentation and / or validations.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.