Skip to content

Commit

Permalink
Bump AJV to v8 (#713)
Browse files Browse the repository at this point in the history
* 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 <essential.randomn3ss@gmail.com>
Co-authored-by: Carmine DiMascio <cdimasci@amazon.com>
  • Loading branch information
3 people committed May 29, 2022
1 parent 3e803b5 commit 2b27332
Show file tree
Hide file tree
Showing 48 changed files with 758 additions and 365 deletions.
16 changes: 8 additions & 8 deletions examples/2-standard-multiple-api-specs/README.md
Expand Up @@ -30,31 +30,31 @@ curl 'localhost:3000/v2/pets?pet_type=kitty' |jq
]

## invoke GET /v2/pets using `type` as specified in v1, but not v2
curl 'localhost:3000/v2/pets?type=cat' |jq
curl 'localhost:3000/v2/pets?type=cat' |jq
{
"message": "Unknown query parameter 'type'",
"errors": [
{
"path": ".query.type",
"path": "/query/type",
"message": "Unknown query parameter 'type'"
}
]
}

## invoke GET /v1/pets using type='kitty'. kitty is not a valid v1 value.
## invoke GET /v1/pets using type='kitty'. kitty is not a valid v1 value.
## also limit is required in GET /v1/pets
curl 'localhost:3000/v1/pets?type=kitty' |jq
{
"message": "request.query.type should be equal to one of the allowed values: dog, cat, request.query should have required property 'limit'",
"message": "request/query/type must be equal to one of the allowed values: dog, cat, request.query must have required property 'limit'",
"errors": [
{
"path": ".query.type",
"message": "should be equal to one of the allowed values: dog, cat",
"path": "/query.type",
"message": "must be equal to one of the allowed values: dog, cat",
"errorCode": "enum.openapi.validation"
},
{
"path": ".query.limit",
"message": "should have required property 'limit'",
"path": "/query.limit",
"message": "must have required property 'limit'",
"errorCode": "required.openapi.validation"
}
]
Expand Down
4 changes: 2 additions & 2 deletions examples/9-nestjs/src/modules/ping/ping.controller.spec.ts
Expand Up @@ -64,8 +64,8 @@ describe('PingController', () => {
path: '/',
errors: [
{
path: '.body.ping',
message: "should have required property 'ping'",
path: '/body/ping',
message: "must have required property 'ping'",
errorCode: 'required.openapi.validation',
},
],
Expand Down
59 changes: 49 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "express-openapi-validator",
"version": "4.13.7",
"version": "4.14.0-beta.1",
"description": "Automatically validate API requests and responses with OpenAPI 3 and Express.",
"main": "dist/index.js",
"scripts": {
Expand Down Expand Up @@ -33,7 +33,9 @@
"license": "MIT",
"dependencies": {
"@types/multer": "^1.4.7",
"ajv": "^6.12.6",
"ajv": "^8.6.2",
"ajv-draft-04": "^1.0.0",
"ajv-formats": "^2.1.1",
"content-type": "^1.0.4",
"json-schema-ref-parser": "^9.0.9",
"lodash.clonedeep": "^4.5.0",
Expand Down
18 changes: 12 additions & 6 deletions src/framework/ajv/formats.ts
Expand Up @@ -14,22 +14,28 @@ const base64regExp = /^[A-Za-z0-9+/]*(=|==)?$/;

export const formats = {
int32: {
validate: i => Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
validate: (i: number) =>
Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
type: 'number',
},
int64: {
validate: i => Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
validate: (i: number) =>
Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
type: 'number',
},
float: {
validate: i => typeof i === 'number' && (i === 0 || (i <= maxFloat && i >= minPosFloat) || (i >= minFloat && i <= maxNegFloat)),
validate: (i: number) =>
typeof i === 'number' &&
(i === 0 ||
(i <= maxFloat && i >= minPosFloat) ||
(i >= minFloat && i <= maxNegFloat)),
type: 'number',
},
double: {
validate: i => typeof i === 'number',
validate: (i: number) => typeof i === 'number',
type: 'number',
},
byte: b => b.length % 4 === 0 && base64regExp.test(b),
byte: (b: string) => b.length % 4 === 0 && base64regExp.test(b),
binary: alwaysTrue,
password: alwaysTrue,
};
} as const;

0 comments on commit 2b27332

Please sign in to comment.