Skip to content

Commit 2b27332

Browse files
JacobLeyEssential Randomnesscdimascio
authored
Bump AJV to v8 (#713)
* try upgrading to OAPIv3.1 * Remove 3.1-support related files * Const typings on formats * Set _discriminator as non-enumerable hide it from AJV (unknown keyword) * Refactor `x-eov-serdes` to ensure order of validation * Update AJV options handling * Update read/write only keywords * Add noop keywords * Use AJV Draft 4 to validate OpenAPI doc * Use `must` keyword to match AJV validations * Expected validation errors prefer `must` over `should`, `/` over `.` * Update README to reflect expected validation errors * Explicitly pass formats to ignore * Serdes validation errors contain more errors * Update example with expected AJV errors * Drop noisy test logs * Restore previous `Format` version * Add failing tests for undeclared x-* keywords Schema declares these are valid (via `patternProperties`) but AJV rejects on any unknown keywords * Detect `x-*` prefixes and declare as noop for Ajv * Update README to declare reserved vendor extension prefix * readOnly+writeOnly do not modify, and do attach errors * Remove test enforcing `x-eov-*` usage README still "reserves" these keywords, but do not explicitly enforce it * Rely on strictSchema=false to handle unknown keywords Remove all NOOP keywords * Explicitly pass strict=false to response validator test Options are usually set internally * Add types to serdes validator, auto-true if missing method * Rework serdes schema processor _slightly_ simplify schema, and document why complexity is necessary. Use custom keywords to allow "redacting" of confusing errors during validation Remove `jsonType` from serdes options (unused) * Update serdes test to reflect simpler validation messages * Consistent usage of / over . for json path Mirroring format of AJV * Add `eov` prefix to unknown query parameters flag Deprecate old version with console.warn * Create "normalized options" type that has stricter format Omits deprecated types/attributes. Allows skipping redundant checks/transforms that were already performed * Set defaults in one place * Add warnings for deprecated usage of options * Move options handling to `normalizeOptions`, add `ajvFormats` option * Update README to reflect new options behavior * Consistent `/` over `.` Matching AJV's internal json path errors * Remove unnecessary serDesInternal check `xEovAnyOf` effectively hides internal schemas and prevents infinite loop * Add `anyOf` test with serdes, expose all relevant errors * Simplify format overriding by applying in order, remove constant * Move redactable error to common types file * Tweak error redacting to only expose most relevant If request is not a string, message should not expose string-centric validations like format (even those "format" is invalid via serialization). Was wrongly exposed in 992cde0 * Refactor serdes (again...) to use keyword execution order So apparently AJV _does_ have some ability to enforce keyword ordering via `before`/`post`! Using those options, serdes schema gets a lot simpler and has more trivial error redacting * v4.14.0-beta.1 Co-authored-by: Essential Randomness <[email protected]> Co-authored-by: Carmine DiMascio <[email protected]>
1 parent 3e803b5 commit 2b27332

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+758
-365
lines changed

examples/2-standard-multiple-api-specs/README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,31 @@ curl 'localhost:3000/v2/pets?pet_type=kitty' |jq
3030
]
3131

3232
## invoke GET /v2/pets using `type` as specified in v1, but not v2
33-
curl 'localhost:3000/v2/pets?type=cat' |jq
33+
curl 'localhost:3000/v2/pets?type=cat' |jq
3434
{
3535
"message": "Unknown query parameter 'type'",
3636
"errors": [
3737
{
38-
"path": ".query.type",
38+
"path": "/query/type",
3939
"message": "Unknown query parameter 'type'"
4040
}
4141
]
4242
}
4343

44-
## invoke GET /v1/pets using type='kitty'. kitty is not a valid v1 value.
44+
## invoke GET /v1/pets using type='kitty'. kitty is not a valid v1 value.
4545
## also limit is required in GET /v1/pets
4646
curl 'localhost:3000/v1/pets?type=kitty' |jq
4747
{
48-
"message": "request.query.type should be equal to one of the allowed values: dog, cat, request.query should have required property 'limit'",
48+
"message": "request/query/type must be equal to one of the allowed values: dog, cat, request.query must have required property 'limit'",
4949
"errors": [
5050
{
51-
"path": ".query.type",
52-
"message": "should be equal to one of the allowed values: dog, cat",
51+
"path": "/query.type",
52+
"message": "must be equal to one of the allowed values: dog, cat",
5353
"errorCode": "enum.openapi.validation"
5454
},
5555
{
56-
"path": ".query.limit",
57-
"message": "should have required property 'limit'",
56+
"path": "/query.limit",
57+
"message": "must have required property 'limit'",
5858
"errorCode": "required.openapi.validation"
5959
}
6060
]

examples/9-nestjs/src/modules/ping/ping.controller.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ describe('PingController', () => {
6464
path: '/',
6565
errors: [
6666
{
67-
path: '.body.ping',
68-
message: "should have required property 'ping'",
67+
path: '/body/ping',
68+
message: "must have required property 'ping'",
6969
errorCode: 'required.openapi.validation',
7070
},
7171
],

package-lock.json

+49-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "express-openapi-validator",
3-
"version": "4.13.7",
3+
"version": "4.14.0-beta.1",
44
"description": "Automatically validate API requests and responses with OpenAPI 3 and Express.",
55
"main": "dist/index.js",
66
"scripts": {
@@ -33,7 +33,9 @@
3333
"license": "MIT",
3434
"dependencies": {
3535
"@types/multer": "^1.4.7",
36-
"ajv": "^6.12.6",
36+
"ajv": "^8.6.2",
37+
"ajv-draft-04": "^1.0.0",
38+
"ajv-formats": "^2.1.1",
3739
"content-type": "^1.0.4",
3840
"json-schema-ref-parser": "^9.0.9",
3941
"lodash.clonedeep": "^4.5.0",

src/framework/ajv/formats.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,28 @@ const base64regExp = /^[A-Za-z0-9+/]*(=|==)?$/;
1414

1515
export const formats = {
1616
int32: {
17-
validate: i => Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
17+
validate: (i: number) =>
18+
Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
1819
type: 'number',
1920
},
2021
int64: {
21-
validate: i => Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
22+
validate: (i: number) =>
23+
Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
2224
type: 'number',
2325
},
2426
float: {
25-
validate: i => typeof i === 'number' && (i === 0 || (i <= maxFloat && i >= minPosFloat) || (i >= minFloat && i <= maxNegFloat)),
27+
validate: (i: number) =>
28+
typeof i === 'number' &&
29+
(i === 0 ||
30+
(i <= maxFloat && i >= minPosFloat) ||
31+
(i >= minFloat && i <= maxNegFloat)),
2632
type: 'number',
2733
},
2834
double: {
29-
validate: i => typeof i === 'number',
35+
validate: (i: number) => typeof i === 'number',
3036
type: 'number',
3137
},
32-
byte: b => b.length % 4 === 0 && base64regExp.test(b),
38+
byte: (b: string) => b.length % 4 === 0 && base64regExp.test(b),
3339
binary: alwaysTrue,
3440
password: alwaysTrue,
35-
};
41+
} as const;

0 commit comments

Comments
 (0)