Skip to content

Commit 2943bbb

Browse files
committed
fix: misc bug fixes
1 parent 232e72a commit 2943bbb

12 files changed

+390
-23
lines changed

packages/ajv-openapi-request-response-validator/src/ajv-openapi-request-response-validator.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,20 @@ function mapValidatorErrors(validatorErrors: ErrorObject[] | null | undefined, s
6363
title: ajvErr.message ?? ET_VALIDATION,
6464
}
6565

66-
if (ajvErr.schemaPath) {
67-
mappedErr.source = {
68-
pointer: ajvErr.schemaPath,
66+
if (ajvErr.schemaPath || ajvErr.params) {
67+
mappedErr.source = {}
68+
69+
if (ajvErr.schemaPath) {
70+
mappedErr.source.pointer = ajvErr.schemaPath
71+
}
72+
if (ajvErr.params) {
73+
const filteredParams = Object.entries(ajvErr.params).filter(([key]) => key === 'additionalProperty' || key === 'missingProperty')
74+
if (filteredParams.length > 0) {
75+
mappedErr.source.parameter = Object.values(ajvErr.params).join(', ')
76+
}
6977
}
7078
}
79+
7180
mapped.push(mappedErr)
7281
})
7382
return mapped

packages/ajv-openapi-request-response-validator/src/openapi-validator.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export function unserializeParameters(parameters: Record<string, Primitive>): Re
143143
const lastKeyIndex = splitKey.length - 1
144144

145145
splitKey.forEach((part, index) => {
146-
const cleanPart = part.replace(']', '')
146+
const cleanPart = part.replace(/]/g, '') // part.replace(']', '')
147147

148148
if (index === lastKeyIndex) {
149149
target[cleanPart] = value
@@ -156,6 +156,7 @@ export function unserializeParameters(parameters: Record<string, Primitive>): Re
156156
})
157157
}
158158
}
159+
159160
return result
160161
}
161162

packages/ajv-openapi-request-response-validator/test/.eslintrc.js

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ module.exports = {
77
},
88
extends: ["../.eslintrc.js"],
99
rules: {
10+
"@typescript-eslint/no-magic-numbers": "off",
11+
"@typescript-eslint/no-explicit-any": "off",
12+
"no-console": "off",
1013
"@typescript-eslint/naming-convention": "off",
1114
"@typescript-eslint/no-non-null-assertion": "off",
1215
}

packages/ajv-openapi-request-response-validator/test/fixtures/example-api.yaml

+150-3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ paths:
7676
schema:
7777
$ref: '#/components/schemas/OneOfExample'
7878

79+
'/one-of-example-list':
80+
get:
81+
responses:
82+
'200':
83+
description: Ok
84+
content:
85+
application/json:
86+
schema:
87+
$ref: '#/components/schemas/OneOfExampleList'
88+
7989
'/all-of-example':
8090
post:
8191
requestBody:
@@ -126,7 +136,8 @@ paths:
126136
schema:
127137
type: object
128138
additionalProperties: true
129-
/users/{uid}/state/{sid}:
139+
140+
'/users/{uid}/state/{sid}':
130141
put:
131142
operationId: put-user-state
132143
summary: Upserts a user state
@@ -151,6 +162,47 @@ paths:
151162
responses:
152163
'200':
153164
description: OK
165+
patch:
166+
operationId: patch-user-state
167+
summary: Patch a user state
168+
parameters:
169+
- name: uid
170+
in: path
171+
required: true
172+
schema:
173+
type: string
174+
- name: sid
175+
in: path
176+
description: The state id or key
177+
required: true
178+
schema:
179+
type: string
180+
requestBody:
181+
content:
182+
application/json:
183+
schema:
184+
type: array
185+
items:
186+
$ref: '#/components/schemas/PatchUserStateValue'
187+
188+
/webhooks/mytest/{provision}:
189+
post:
190+
parameters:
191+
- name: provision
192+
in: path
193+
required: true
194+
schema:
195+
type: string
196+
requestBody:
197+
content:
198+
application/json:
199+
schema:
200+
$ref: '#/components/schemas/MyTestProvisionResponse'
201+
required: true
202+
responses:
203+
'200':
204+
description: OK
205+
154206
components:
155207
responses:
156208
ResponseError:
@@ -347,6 +399,14 @@ components:
347399
discriminator:
348400
propertyName: objType
349401

402+
OneOfExampleList:
403+
type: object
404+
properties:
405+
items:
406+
type: array
407+
items:
408+
$ref: '#/components/schemas/OneOfExample'
409+
350410
AllOfExample:
351411
type: object
352412
description: Example using allOf
@@ -358,11 +418,13 @@ components:
358418
status:
359419
type: string
360420
enum: [pending, approved, rejected]
421+
361422
UserStateValue:
362423
type: "object"
363424
oneOf:
364425
- $ref: '#/components/schemas/UserStateCoffeeCx'
365426
- $ref: '#/components/schemas/UserUploads'
427+
- $ref: '#/components/schemas/UserStateWidgets'
366428
discriminator:
367429
propertyName: type
368430
UserStateCoffeeCx:
@@ -376,7 +438,10 @@ components:
376438
enum: [coffeeCx]
377439
enabled:
378440
type: boolean
379-
description: Whether a certain flag, feature, etc. is enabled or not
441+
description: Whether a certain flag, feature, etc. is enabled or not
442+
nullableTest:
443+
type: string
444+
nullable: true
380445
UserUploads:
381446
type: object
382447
required:
@@ -428,4 +493,86 @@ components:
428493
description: >-
429494
A valid path that matches any sequence of characters except if it
430495
contains '../', '//' (to avoid directory traversal attacks)
431-
maxLength: 255
496+
maxLength: 255
497+
UserStateWidgets:
498+
type: object
499+
required:
500+
- type
501+
- widgets
502+
properties:
503+
type:
504+
type: string
505+
enum:
506+
- widgets
507+
widgets:
508+
type: array
509+
items:
510+
type: string
511+
oneOf:
512+
- minItems: 4
513+
maxItems: 4
514+
- minItems: 3
515+
maxItems: 3
516+
- minItems: 2
517+
maxItems: 2
518+
AnyValue:
519+
description: Accepts any valid JSON value
520+
additionalProperties: true
521+
oneOf:
522+
- type: string
523+
- type: number
524+
- type: integer
525+
- type: boolean
526+
- type: array
527+
items:
528+
$ref: '#/components/schemas/AnyValue'
529+
- type: object
530+
additionalProperties: true
531+
PatchUserStateValue:
532+
type: object
533+
required:
534+
- op
535+
- path
536+
- value
537+
properties:
538+
op:
539+
type: string
540+
enum:
541+
- replace
542+
- add
543+
- remove
544+
path:
545+
type: string
546+
value:
547+
$ref: '#/components/schemas/AnyValue'
548+
MyTestProvisionResponse:
549+
type: object
550+
required:
551+
- taskId
552+
properties:
553+
taskId:
554+
type: string
555+
stateBag:
556+
type: object
557+
required:
558+
- contentEntryId
559+
properties:
560+
contentEntryId:
561+
type: string
562+
guestUserUid:
563+
type: string
564+
siteInfo:
565+
type: object
566+
required:
567+
- url
568+
properties:
569+
url:
570+
type: string
571+
teamId:
572+
type: string
573+
groupId:
574+
type: string
575+
errorMessage:
576+
description: Reason why the job failed.
577+
type: string
578+

packages/ajv-openapi-request-response-validator/test/fixtures/fail-requestBody-allof-with-schema.js.txt

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ module.exports = {
109109
{
110110
"code": "Validation-additionalProperties",
111111
"source": {
112+
"parameter": "bark",
112113
"pointer": "#/components/schemas/Cat/additionalProperties",
113114
},
114115
"status": 400,

packages/ajv-openapi-request-response-validator/test/fixtures/fail-requestBody-anyof-with-schema.js.txt

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ module.exports = {
7676
{
7777
"code": "Validation-required",
7878
"source": {
79+
"parameter": "age",
7980
"pointer": "#/components/schemas/PetByAge/required",
8081
},
8182
"status": 400,
@@ -84,6 +85,7 @@ module.exports = {
8485
{
8586
"code": "Validation-required",
8687
"source": {
88+
"parameter": "pet_type",
8789
"pointer": "#/components/schemas/PetByType/required",
8890
},
8991
"status": 400,

packages/ajv-openapi-request-response-validator/test/fixtures/fail-requestBody-oneof-with-schema.js.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ module.exports = {
6666
},
6767
},
6868
expectedErrors: [
69-
{"code": "Validation-additionalProperties", "source": {"pointer": "#/components/schemas/Cat/additionalProperties"}, "status": 400, "title": "must NOT have additional properties"}, {"code": "Validation-additionalProperties", "source": {"pointer": "#/components/schemas/Dog/additionalProperties"}, "status": 400, "title": "must NOT have additional properties"}, {"code": "Validation-oneOf", "source": {"pointer": "#/oneOf"}, "status": 400, "title": "must match exactly one schema in oneOf"}
69+
{"code": "Validation-additionalProperties", "source": {"pointer": "#/components/schemas/Cat/additionalProperties", "parameter": "breed",}, "status": 400, "title": "must NOT have additional properties"}, {"code": "Validation-additionalProperties", "source": {"pointer": "#/components/schemas/Dog/additionalProperties", "parameter": "age"}, "status": 400, "title": "must NOT have additional properties"}, {"code": "Validation-oneOf", "source": {"pointer": "#/oneOf"}, "status": 400, "title": "must match exactly one schema in oneOf"}
7070
]
7171
};

packages/ajv-openapi-request-response-validator/test/fixtures/fail-requestBody-with-components-default.js.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ module.exports = {
3131
expectedErrors: [
3232
{
3333
code: 'Validation-additionalProperties',
34-
source: {
34+
source: {
35+
"parameter": "something-else",
3536
pointer: '#/components/schemas/Test1/additionalProperties'
3637
},
3738
status: 400,

packages/ajv-openapi-request-response-validator/test/fixtures/fail-requestBody-with-components-ref.js.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ module.exports = {
2828
expectedErrors: [
2929
{
3030
code: 'Validation-required',
31-
source: {
31+
source: {
32+
"parameter": "foo",
3233
pointer: '#/components/schemas/Test1/required'
3334
},
3435
status: 400,

packages/ajv-openapi-request-response-validator/test/unit/ajv-validator-api.spec.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
/* eslint-disable @typescript-eslint/no-explicit-any */
21
import * as fs from 'fs'
3-
import * as path from 'path'
2+
import * as nodepath from 'path'
43
import { OpenAPIV3 } from 'openapi-types'
54
import copy from 'fast-copy'
65
import { createAjvInstance } from '../../src/ajv-factory'
@@ -64,8 +63,8 @@ const files = fs.readdirSync(fixtureDir)
6463
const testCases: { [key: string]: TestFixture } = {}
6564
for (const file of files) {
6665
if (file.endsWith('.js.txt')) {
67-
const testName = path.basename(file, '.js.txt').replace(/-/g, ' ')
68-
const fixtureContent = fs.readFileSync(path.resolve(fixtureDir, file), { encoding: 'utf-8' })
66+
const testName = nodepath.basename(file, '.js.txt').replace(/-/g, ' ')
67+
const fixtureContent = fs.readFileSync(nodepath.resolve(fixtureDir, file), { encoding: 'utf-8' })
6968
try {
7069
// eslint-disable-next-line no-eval
7170
const fixture: TestFixture = eval(fixtureContent)
@@ -116,14 +115,14 @@ describe('The api validator', () => {
116115

117116
if (fixture.validateArgs.paths) {
118117
const params = fixture.request.query ? fixture.request.query : {}
119-
for (const [methodPath, method] of Object.entries(fixture.validateArgs.paths)) {
118+
for (const [path, method] of Object.entries(fixture.validateArgs.paths)) {
120119
if (method) {
121120
for (const [methodName, methodDef] of Object.entries(method)) {
122121
if (Object.values(OpenAPIV3.HttpMethods).includes(methodName as OpenAPIV3.HttpMethods)) {
123122
const operation: OpenAPIV3.OperationObject<object> = methodDef
124123
if (operation.parameters) {
125124
const result = validator.validateQueryParams(
126-
methodPath,
125+
path,
127126
methodName,
128127
params,
129128
fixture.requestOpts?.strictQueryParamValidation ?? true
@@ -136,7 +135,7 @@ describe('The api validator', () => {
136135
}
137136
if (operation.requestBody && fixture.request.body) {
138137
const result = validator.validateRequestBody(
139-
methodPath,
138+
path,
140139
methodName,
141140
fixture.request.body,
142141
fixture.requestOpts?.strictRequestBodyValidation ?? true

0 commit comments

Comments
 (0)