Skip to content

Commit 2005c1b

Browse files
cdimasciocrudo
authored andcommitted
fix: top level default values for deep objects (#586)
1 parent 8b7ad7d commit 2005c1b

File tree

3 files changed

+84
-23
lines changed

3 files changed

+84
-23
lines changed

src/middlewares/parsers/req.parameter.mutator.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,39 @@ export class RequestParameterMutator {
103103
});
104104
}
105105

106-
private handleDeepObject(req: Request, qs: string, name: string, schema: SchemaObject): void {
106+
private handleDeepObject(
107+
req: Request,
108+
qs: string,
109+
name: string,
110+
schema: SchemaObject,
111+
): void {
107112
const getDefaultSchemaValue = () => {
108113
let defaultValue;
109114

110115
if (schema.default !== undefined) {
111-
defaultValue = schema.default
116+
defaultValue = schema.default;
117+
} else if (schema.properties) {
118+
Object.entries(schema.properties).forEach(([k, v]) => {
119+
// Handle recursive objects
120+
defaultValue ??= {};
121+
if (v['default']) {
122+
defaultValue[k] = v['default'];
123+
}
124+
});
112125
} else {
113126
['allOf', 'oneOf', 'anyOf'].forEach((key) => {
114127
if (schema[key]) {
115128
schema[key].forEach((s) => {
116129
if (s.$ref) {
117130
const compiledSchema = this.ajv.getSchema(s.$ref);
118131
// as any -> https://stackoverflow.com/a/23553128
119-
defaultValue = defaultValue === undefined ? (compiledSchema.schema as any).default : defaultValue;
132+
defaultValue =
133+
defaultValue === undefined
134+
? (compiledSchema.schema as any).default
135+
: defaultValue;
120136
} else {
121-
defaultValue = defaultValue === undefined ? s.default : defaultValue;
137+
defaultValue =
138+
defaultValue === undefined ? s.default : defaultValue;
122139
}
123140
});
124141
}

test/resources/serialized-deep-object.objects.yaml

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,47 @@ paths:
4040
responses:
4141
"200":
4242
description: the object
43+
/deep_object_2:
44+
get:
45+
parameters:
46+
- $ref: '#/components/parameters/pedestrian'
47+
responses:
48+
"200":
49+
description: the object
4350

4451
components:
4552
schemas:
46-
Deep:
53+
Pedestrian:
4754
type: object
4855
properties:
49-
tag_ids:
50-
type: array
51-
items:
52-
type: integer
53-
minimum: 0
54-
minItems: 1
55-
state:
56-
type: string
57-
enum: ["default", "validated", "pending"]
58-
default: "default"
59-
description: "Filter the tags by their validity. The default value ('default') stands for no filtering."
60-
greeting:
61-
type: string
62-
default: "hello"
56+
speed:
57+
type: number
58+
format: double
59+
minimum: 0.5
60+
maximum: 2
61+
default: 1
62+
# Deep:
63+
# type: object
64+
# properties:
65+
# tag_ids:
66+
# type: array
67+
# items:
68+
# type: integer
69+
# minimum: 0
70+
# minItems: 1
71+
# state:
72+
# type: string
73+
# enum: ["default", "validated", "pending"]
74+
# default: "default"
75+
# description: "Filter the tags by their validity. The default value ('default') stands for no filtering."
76+
# greeting:
77+
# type: string
78+
# default: "hello"
79+
80+
parameters:
81+
pedestrian:
82+
name: pedestrian
83+
in: query
84+
style: deepObject
85+
schema:
86+
$ref: '#/components/schemas/Pedestrian'

test/serialized-deep-object.objects.spec.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ describe(packageJson.name, () => {
1010

1111
before(async () => {
1212
// Set up the express app
13-
const apiSpec = path.join('test', 'resources', 'serialized-deep-object.objects.yaml');
13+
const apiSpec = path.join(
14+
'test',
15+
'resources',
16+
'serialized-deep-object.objects.yaml',
17+
);
1418
app = await createApp({ apiSpec }, 3005, (app) =>
1519
app.use(
1620
`${app.basePath}`,
1721
express
1822
.Router()
1923
.get(`/deep_object`, (req, res) => res.json(req.query))
24+
.get(`/deep_object_2`, (req, res) => res.json(req.query)),
2025
),
2126
);
2227
});
@@ -25,6 +30,16 @@ describe(packageJson.name, () => {
2530
app.server.close();
2631
});
2732

33+
it('should explode deepObject and set default', async () =>
34+
request(app)
35+
.get(`${app.basePath}/deep_object_2`)
36+
.expect(200)
37+
.then((r) => {
38+
expect(r.body).to.deep.equals({
39+
pedestrian: { speed: 1 },
40+
});
41+
}));
42+
2843
it('should explode deepObject query params', async () =>
2944
request(app)
3045
.get(`${app.basePath}/deep_object?settings[state]=default`)
@@ -33,8 +48,8 @@ describe(packageJson.name, () => {
3348
const expected = {
3449
settings: {
3550
greeting: 'hello',
36-
state: 'default'
37-
}
51+
state: 'default',
52+
},
3853
};
3954
expect(r.body).to.deep.equals(expected);
4055
}));
@@ -45,6 +60,11 @@ describe(packageJson.name, () => {
4560
.expect(200)
4661
.then((r) => {
4762
const expected = {};
48-
expect(r.body).to.deep.equals(expected);
63+
expect(r.body).to.deep.equals({
64+
settings: {
65+
greeting: 'hello',
66+
state: 'default',
67+
},
68+
});
4969
}));
5070
});

0 commit comments

Comments
 (0)