simonplend / express-json-validator-middleware Goto Github PK
View Code? Open in Web Editor NEWExpress middleware for validating requests against JSON schema
Home Page: https://npm.im/express-json-validator-middleware
License: MIT License
Express middleware for validating requests against JSON schema
Home Page: https://npm.im/express-json-validator-middleware
License: MIT License
Hello,
I'm trying to use the email format, but no success.
Here's the schema:
{ "type": "object", "required": ["email", "password"], "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string" } } }
Then when the server is starting (even before any request), I get this error:
Error: unknown format "email" ignored in schema at path "#/properties/email"
My Validator is being stantiated with this:
const { validate } = new Validator({ allErrors: true });
If I remove "format": "email" from the schema, validation works fine.
What I'm doing wrong?
Edit: already installed ajv-formats package too, but no success; I don't know how to add the formats I would like to use and connect with the middleware.
Can you update to ajv 6?
As per the npm documentation:
...
package-lock.json
cannot be published, and it will be ignored if found in any place other than the root project.
This means that you will have no idea this property exists unless you notice it in the README: https://github.com/simonplend/express-json-validator-middleware#ajv-instance
Access to the Ajv instance is required for configuring Ajv plugins, so it's important that it's intuitive for users of this library to access i.e. by it having an explicit type definition.
User is able to define a custom keyword to be used in schemas.
I'm trying to use dynamic schemas as described in the documentation:
function loadAccountSchema(req, res, next) {
try {
if (req.body.accountType === 'personal') {
req.schema = accountSchema.Insert;
}
else {
req.schema = accountSchema.InsertCorporate;
}
next();
} catch (error) {
next(error);
}
}
function getSchema(req) {
// return the schema from the previous middleware or the default schema
return req.schema || DefaultSchema;
}
app.post('/account/:uId', loadAccountSchema, validate({ body: getSchema }), function(
req, res ) {
However I get this error when I try to run express:
/home/solomon/Development/trippinc/firebase-backend/src/main/functions/node_modules/ajv/lib/ajv.js:303
throw new Error('schema should be object or boolean');
^
Error: schema should be object or boolean
at Ajv._addSchema (/home/solomon/Development/trippinc/firebase-backend/src/main/functions/node_modules/ajv/lib/ajv.js:303:11)
at Ajv.compile (/home/solomon/Development/trippinc/firebase-backend/src/main/functions/node_modules/ajv/lib/ajv.js:117:24)
at Validator.<anonymous> (/home/solomon/Development/trippinc/firebase-backend/src/main/functions/node_modules/express-json-validator-middleware/src/index.js:24:36)
at Array.map (native)
at Validator.validate (/home/solomon/Development/trippinc/firebase-backend/src/main/functions/node_modules/express-json-validator-middleware/src/index.js:22:50)
at module.exports (/home/solomon/Development/trippinc/firebase-backend/src/main/functions/usermgmt.js:86:48)
Any ideas whats going on?
User is able to pass in an options object containing Ajv options on initilalization.
Hi! I would like to ask about this Error i'm currently having on my project.
const validateFunctions = Object.keys(options).map(function (requestProperty) {
^
TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
at Validator.validate (C:\xampp\htdocs\siakad-new\node_modules\express-json-validator-middleware\src\index.js:24:42)
at Object.<anonymous> (C:\xampp\htdocs\siakad-new\routes\users_route.js:25:54)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:692:17)
at require (internal/modules/cjs/helpers.js:25:18)
[nodemon] app crashed - waiting for file changes before starting...
I tried to do exactly the same approach like in the README, but still got this Error.
const { validate } = require('../config/validator');
router.get('/:id', validate({ params: UsersSchema.getUsersById.params }), validate(UsersSchema.getUserById), UsersController.getUserById);
Am i missing something here actually?
Any replies would be helpful.
This library is currently using Ajv v6. Upgrading to Ajv v7 was proposed in pull request #55. In the meantime, Ajv v8 has been released, so we'll upgrade to that.
See: Changes from Ajv v6.12.6 to v8.0.0
Some of these may be worth breaking out into separate issues.
v8.8.2
)
where are the formats coming from? more specifically where is the alphanumeric coming from?
It appears to me you might have an issue with calling a function that sets the headers in your error path, because whenever I try to change the error status in the error handler I get:
cannot 400 after headers sent
The documentation on this stuff is pretty confusing. I'm returning promises in my API handler and there's no error being thrown there. My error handler looks like this:
app.use(function(err, req, res, next) {
console.log(JSON.stringify(err));
if (err && err.name && err.name == 'JsonSchemaValidationError') {
console.log('-------- sending 400: ', res.headersSent); // show false
//return res.sendStatus(400).json(err.validationErrors).end();
return res.json(err.validationErrors).sendStatus(400);
} else {
log.info({err: err}, 'uncaught exception');
return res.sendStatus(500);
}
});
It's no longer running since #77 was merged.
Potential package-support.json
:
{
"versions": [
{
"version": "*",
"target": {
"node": "supported"
},
"response": {
"type": "best-effort"
},
"backing": {
"none": ""
}
}
]
}
Add "support": true
to package.json
.
ajv-formats
I'm new to JSON schema validation, but according to this website there is a date-time
type. But I get an error when I use this in my schema declaration.
module.exports = {
type: 'object',
properties: {
startedAt: {
type: 'date-time',
},
// ...
};
error:
Error: schema is invalid: data.properties['startedAt'].type should be equal to one of the allowed values, data.properties['startedAt'].type should be array, data.properties['startedAt'].type should match some schema in anyOf
Is there a documentation saying which types are supported?
Would be great if you could provide regex support as part of the middleware. So, I can specify my own rules for certain validations.
This name@com
should throw an error.
2.0.0 works great but once updated to 2.1.0 I got strange errors from ts compiler.
Type '{ type: string; required: string[]; properties: { firstName: { type: string; }; lastName: { type: string; }; email: { type: string; }; phone: { type: string[]; }; password: { type: string; }; participantId: { type: string; }; }; }' is not assignable to type 'ValidateFunction'.
Type '{ type: string; required: string[]; properties: { firstName: { type: string; }; lastName: { type: string; }; email: { type: string; }; phone: { type: string[]; }; password: { type: string; }; participantId: { type: string; }; }; }' is not assignable to type 'JSONSchema7'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type '"string" | "number" | "boolean" | "object" | "integer" | "null" | "array" | JSONSchema7TypeName[]'.
The v2.2.0 release of this package accidentally included two large unrelated JSON files. This bloated the package size from 37.9 kB to 7.63 MB.
We should set a files
field in package.json
to restrict which files are published for this package. We can then remove the .npmignore
file, as it's not a safe way of controlling what is published.
$ curl -s (npm view [email protected] dist.tarball) | tar tzvf -
-rw-r--r-- 0/0 375 1985-10-26 09:15 package/.editorconfig
-rw-r--r-- 0/0 1089 1985-10-26 09:15 package/LICENSE
-rw-r--r-- 0/0 1902 1985-10-26 09:15 package/src/index.js
-rw-r--r-- 0/0 59 1985-10-26 09:15 package/.prettierrc.json
-rw-r--r-- 0/0 3760933 1985-10-26 09:15 package/file:/home/simonplend/.config/Code/User/globalStorage/amazonwebservices.aws-toolkit-vscode/cloudformation.schema.json
-rw-r--r-- 0/0 1435 1985-10-26 09:15 package/package.json
-rw-r--r-- 0/0 3854508 1985-10-26 09:15 package/file:/home/simonplend/.config/Code/User/globalStorage/amazonwebservices.aws-toolkit-vscode/sam.schema.json
-rw-r--r-- 0/0 525 1985-10-26 09:15 package/docs/migrating-from-express-jsonschema.md
-rw-r--r-- 0/0 8431 1985-10-26 09:15 package/README.md
-rw-r--r-- 0/0 2695 1985-10-26 09:15 package/patreon.png
-rw-r--r-- 0/0 830 1985-10-26 09:15 package/src/index.d.ts
-rw-r--r-- 0/0 636 1985-10-26 09:15 package/.github/workflows/ci.yml
-rw-r--r-- 0/0 1 1985-10-26 09:15 package/.github/FUNDING.yml
Exactly this. Having to create another middleware just to return a "precursor" schema, or some component of a schema, is potentially tedious and error-prone (what happens if I forget to add the "precursor" middleware to my route?), and can result in related logic being split into unrelated places.
To this end, an enhancement I'd appreciate is the ability to return a Promise from a dynamic schema generator function. Then, the middleware can await
the Promise (or the synchronous return, in the existing case) and do the usual compile -> validate -> next()
thing.
package.json
- repository
, bugs
, homepage
LICENSE
- Maintainer name.editorconfig
This is a retread of #31, but with some actually concrete proposals and rationale.
Currently, it is only possible to provide either literal schemas, or schemas from synchronous functions. If a schema requires (e.g.) a database read, the only way to do it is to perform the operation in a prior middleware, then pass it along by mutating the request object (or to wrap this middleware in something custom). This is sub-optimal for a few reasons:
My proposed solution to this is fairly straightforward: allow passing Promises of a schema, or functions that return Promises of a schema. In TypeScript terms, changing this (borrowed from #72 for easier readability):
type AllowedSchema =
| JSONSchema4
| JSONSchema6
| JSONSchema7;
export type ValidateFunction =
| ((req: Request) => AllowedSchema)
| AllowedSchema;
to this:
type AllowedSchema =
| JSONSchema4
| JSONSchema6
| JSONSchema7;
export type ValidateFunction =
| ((req: Request) => AllowedSchema | Promise<AllowedSchema>)
| Promise<AllowedSchema>
| AllowedSchema;
Then, the request handler can await
the Promise, and perform the normal operation.
I found out that ValidationError is extended from the Error instance.
If you do this below in TypeScript:
const validationError = new ValidationError({
params: [{
dataPath: '.id',
keyword: 'maxLength',
message: 'should NOT be longer than 2 characters',
params: { limit: 2 },
schemaPath: '#/properties/id/maxLength'
}]
})
It will throw a ts compile error because the argument type should be a string.
To fix this problem, I just add // @ts-ignore
before new ValidationError
.
Any better support for this?
It would be great to have support for readOnly
and writeOnly
keywords as described on the OpenApi site
You can use the readOnly and writeOnly keywords to mark specific properties as read-only or write-only. This is useful, for example, when GET returns more properties than used in POST โ you can use the same schema in both GET and POST and mark the extra properties as readOnly. readOnly properties are included in responses but not in requests, and writeOnly properties may be sent in requests but not in responses.
Create a CONTRIBUTING.md
Inspiration:
Originating from #15
While it may provide a performance benefit (not having to validate after the first error is found), from my experience the user usually wants to work with errors from all req properties.
If we implement this feature, I would like to make it configurable by introducing an options object for the Validator instance, and also make it off by default.
Thoughts?
I was wondering if the library supports JSON Schema default values, and if so how would one use them?
I've tried simply setting defaults in the schema declaration, however after passing the validation middleware and trying to access the properties on the effect ( logic middleware ) the properties still dont exist.
Am I doing something wrong or is it not supported / implemented?
const schema = {
type: 'object',
required: ['foo'],
properties: {
foo: { type: 'string' },
bar: { type: 'string', default: 'Bar' }
}
};
app.post('/foo', validate({body: schema}), (req, res) => {
console.log(req.data);
});
Above will output { foo: "Foo" }
for a post with the following data sent { "foo": "Foo" }
, while I would expect it should print { foo: "Foo", bar: "Bar" }
Investigate into possible performance improvements:
- Best way to compile the schema and check for errors
Revise JSDocs in source
Simplify docs in README
AJV has a plugin system, along the lines of the decorator pattern - each plugin exposes a function that modifies an instantiated Ajv
object. However, because the Validator
class only accepts AjvOptions
and then constructs its own, applying plugins requires modifying it at runtime. This is fine (and expected, according to the tests) in straight JavaScript, but in TypeScript violates the provided types, because the Ajv
is not included in the class definition:
// Plugin
import formats from "ajv-formats-draft2019";
const ajv = formats(new Ajv({allErrors: true}));
const validator = new Validator({});
validator.ajv = ajv;
// Yields:
// TS2339: Property 'ajv' does not exist on type 'Validator'.
Either way, this seems a brittle approach, prone to breaking as the library changes. A backwards-compatible solution to this might be something like:
export class Validator {
// Allow passing an Ajv to the constructor
constructor(options: AjvOptions | Ajv);
// Expose the ajv to match the behaviour of the JS implementation
ajv: Ajv;
}
If a non-Ajv
object is provided, the existing behaviour is kept, but otherwise the validator can just use the provided Ajv
wholesale.
I've tried the library and it works perfectly with normal js, but throws type errors when using ts.
The type error occurs at addressSchema
when passing it to body
. Is there something I missed?
Type '{ readonly type: "object"; readonly required: readonly ["number", "street", "type"]; readonly properties: { readonly number: { readonly type: "number"; }; readonly street: { readonly type: "string"; }; readonly type: { ...; }; }; }' is not assignable to type 'ValidateFunction | undefined'.
Type '{ readonly type: "object"; readonly required: readonly ["number", "street", "type"]; readonly properties: { readonly number: { readonly type: "number"; }; readonly street: { readonly type: "string"; }; readonly type: { ...; }; }; }' is not assignable to type 'JSONSchema7'.
Types of property 'required' are incompatible.
The type 'readonly ["number", "street", "type"]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
import express from "express";
import { Validator, ValidationError } from "express-json-validator-middleware";
const app = express();
app.use(express.json());
const addressSchema = {
type: "object",
required: ["number", "street", "type"],
properties: {
number: {
type: "number",
},
street: {
type: "string",
},
type: {
type: "string",
enum: ["Street", "Avenue", "Boulevard"],
},
},
} as const;
const { validate } = new Validator({});
app.post("/address", validate({ body: addressSchema }), (request, response) => {
response.send({});
});
app.listen(3000);
Related: issue #112
Remaining issues to complete: Release v3.0.0 milestone
The code examples in the README need modernising.
Check Ajv v8.x compatibility.
Things to consider:
package.json
- engines.node
.github/workflows/ci.yml
In the npm and yarn docs the readme numbering is not incrementing correctly like it does for github in the getting started section
Hi,
I've been trying for a while to setup so I can post a custom errormessage ith the validationErrors but I can't seem to get it to work. I'm not sure what I'm doing wrong. Is there any examples of this?
Import everything;
const { Validator } = require('express-json-validator-middleware');
const { validate } = new Validator();
Create the scheme to validate against,
exports.test = {
type: 'object',
required: ['name'],
properties: {
name: {
type: 'string',
},
},
errorMessage: 'This is the message I want to pass on and overwrite the standard one..',
};
Set it up as a middleware
router.get('/test', validate({ body: userValidator.test }), userController.test);
And this is the response,
"error": {
"name": "JsonSchemaValidationError",
"validationErrors": {
"body": [
{
"keyword": "required",
"dataPath": "",
"schemaPath": "#/required",
"params": {
"missingProperty": "name"
},
"message": "should have required property 'name'"
}
]
},
I tried following this: https://github.com/simonplend/express-json-validator-middleware#ajv-instance, but that didn't solve it (honestly the ajv-instance just crashes the server.
Running a node server (v14.15.4), with express(v4.17.1)
Most likely I'm missing out some really basic part but an anyone help me out with how to get this package working with a custom errormessage?
Thanks in advance!
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.