Skip to content

Commit c16ab96

Browse files
Fix cdimascio#699 serdes missed on items in a collection.
1 parent 32d2299 commit c16ab96

File tree

3 files changed

+410
-1
lines changed

3 files changed

+410
-1
lines changed

src/middlewares/parsers/schema.preprocessor.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type Schema = ReferenceObject | SchemaObject;
5656
if (!Array.prototype['flatMap']) {
5757
// polyfill flatMap
5858
// TODO remove me when dropping node 10 support
59-
Array.prototype['flatMap'] = function (lambda) {
59+
Array.prototype['flatMap'] = function(lambda) {
6060
return Array.prototype.concat.apply([], this.map(lambda));
6161
};
6262
Object.defineProperty(Array.prototype, 'flatMap', { enumerable: false });
@@ -199,6 +199,9 @@ export class SchemaPreprocessor {
199199
const child = new Node(node, s, [...node.path, 'anyOf', i + '']);
200200
recurse(node, child, opts);
201201
});
202+
} else if (/*schema.type == 'array' && */ schema.items) {
203+
const child = new Node(node, schema.items, [...node.path, 'items']);
204+
recurse(node, child, opts);
202205
} else if (schema.properties) {
203206
Object.entries(schema.properties).forEach(([id, cschema]) => {
204207
const path = [...node.path, 'properties', id];

test/699.spec.ts

+335
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
import * as path from 'path';
2+
import { expect } from 'chai';
3+
import * as request from 'supertest';
4+
import { createApp } from './common/app';
5+
6+
import { date, dateTime } from '../src/framework/base.serdes';
7+
8+
const apiSpecPath = path.join('test', '699.yaml');
9+
10+
class ObjectID {
11+
id: string;
12+
13+
constructor(id: string = "5fdefd13a6640bb5fb5fa925") {
14+
this.id = id;
15+
}
16+
17+
toString() {
18+
return this.id;
19+
}
20+
21+
}
22+
23+
class BadDate extends Date {
24+
public toISOString(): string {
25+
return "oh no a bad iso date";
26+
}
27+
}
28+
29+
describe('699', () => {
30+
let app = null;
31+
32+
before(async () => {
33+
// set up express app
34+
app = await createApp(
35+
{
36+
apiSpec: apiSpecPath,
37+
validateRequests: {
38+
coerceTypes: true
39+
},
40+
validateResponses: {
41+
coerceTypes: true
42+
},
43+
serDes: [
44+
date,
45+
dateTime,
46+
{
47+
format: "mongo-objectid",
48+
deserialize: (s) => new ObjectID(s),
49+
serialize: (o) => o.toString(),
50+
},
51+
],
52+
},
53+
3005,
54+
(app) => {
55+
app.get([`${app.basePath}/users/:id?`], (req, res) => {
56+
if (typeof req.params.id !== 'object') {
57+
throw new Error("Should be deserialized to ObjectId object");
58+
}
59+
let date = new Date("2020-12-20T07:28:19.213Z");
60+
res.json({
61+
id: req.params.id,
62+
creationDateTime: date,
63+
creationDate: date,
64+
history: [{
65+
modificationDate: date
66+
}],
67+
});
68+
});
69+
app.post([`${app.basePath}/users`], (req, res) => {
70+
if (typeof req.body.id !== 'object') {
71+
throw new Error("Should be deserialized to ObjectId object");
72+
}
73+
if (typeof req.body.creationDate !== 'object' || !(req.body.creationDate instanceof Date)) {
74+
throw new Error("Should be deserialized to Date object");
75+
}
76+
if (typeof req.body.creationDateTime !== 'object' || !(req.body.creationDateTime instanceof Date)) {
77+
throw new Error("Should be deserialized to Date object");
78+
}
79+
res.json(req.body);
80+
});
81+
app.use((err, req, res, next) => {
82+
console.error(err)
83+
res.status(err.status ?? 500).json({
84+
message: err.message,
85+
code: err.status ?? 500,
86+
});
87+
});
88+
},
89+
false,
90+
);
91+
return app
92+
});
93+
94+
after(() => {
95+
app.server.close();
96+
});
97+
98+
it('should control BAD id format and throw an error', async () =>
99+
request(app)
100+
.get(`${app.basePath}/users/1234`)
101+
.expect(400)
102+
.then((r) => {
103+
expect(r.body.message).to.equal('request.params.id should match pattern "^[0-9a-fA-F]{24}$"');
104+
}));
105+
106+
it('should control GOOD id format and get a response in expected format', async () =>
107+
request(app)
108+
.get(`${app.basePath}/users/5fdefd13a6640bb5fb5fa925`)
109+
.expect(200)
110+
.then((r) => {
111+
expect(r.body.id).to.equal('5fdefd13a6640bb5fb5fa925');
112+
expect(r.body.creationDate).to.equal('2020-12-20');
113+
expect(r.body.creationDateTime).to.equal("2020-12-20T07:28:19.213Z");
114+
expect(r.body.history[0].modificationDate).to.equal("2020-12-20");
115+
}));
116+
117+
it('should POST also works with deserialize on request then serialize en response', async () =>
118+
request(app)
119+
.post(`${app.basePath}/users`)
120+
.send({
121+
id: '5fdefd13a6640bb5fb5fa925',
122+
creationDateTime: '2020-12-20T07:28:19.213Z',
123+
creationDate: '2020-12-20'
124+
})
125+
.set('Content-Type', 'application/json')
126+
.expect(200)
127+
.then((r) => {
128+
expect(r.body.id).to.equal('5fdefd13a6640bb5fb5fa925');
129+
expect(r.body.creationDate).to.equal('2020-12-20');
130+
expect(r.body.creationDateTime).to.equal("2020-12-20T07:28:19.213Z");
131+
}));
132+
133+
it('should POST throw error on invalid schema ObjectId', async () =>
134+
request(app)
135+
.post(`${app.basePath}/users`)
136+
.send({
137+
id: '5fdefd13a6640bb5fb5fa',
138+
creationDateTime: '2020-12-20T07:28:19.213Z',
139+
creationDate: '2020-12-20'
140+
})
141+
.set('Content-Type', 'application/json')
142+
.expect(400)
143+
.then((r) => {
144+
expect(r.body.message).to.equal('request.body.id should match pattern "^[0-9a-fA-F]{24}$"');
145+
}));
146+
147+
it('should POST throw error on invalid schema Date', async () =>
148+
request(app)
149+
.post(`${app.basePath}/users`)
150+
.send({
151+
id: '5fdefd13a6640bb5fb5fa925',
152+
creationDateTime: '2020-12-20T07:28:19.213Z',
153+
creationDate: '2020-1f-20'
154+
})
155+
.set('Content-Type', 'application/json')
156+
.expect(400)
157+
.then((r) => {
158+
expect(r.body.message).to.equal('request.body.creationDate should match format "date"');
159+
}));
160+
161+
});
162+
163+
164+
165+
describe('serdes serialize response components only', () => {
166+
let app = null;
167+
168+
before(async () => {
169+
// set up express app
170+
app = await createApp(
171+
{
172+
apiSpec: apiSpecPath,
173+
validateRequests: {
174+
coerceTypes: true
175+
},
176+
validateResponses: {
177+
coerceTypes: true
178+
},
179+
serDes: [
180+
date.serializer,
181+
dateTime.serializer,
182+
{
183+
format: "mongo-objectid",
184+
serialize: (o) => o.toString(),
185+
},
186+
],
187+
unknownFormats: ['mongo-objectid'],
188+
},
189+
3005,
190+
(app) => {
191+
app.get([`${app.basePath}/users/:id?`], (req, res) => {
192+
if (typeof req.params.id !== 'string') {
193+
throw new Error("Should be not be deserialized to ObjectId object");
194+
}
195+
let date = new Date("2020-12-20T07:28:19.213Z");
196+
let result = {
197+
id: new ObjectID(req.params.id),
198+
creationDateTime: date,
199+
creationDate: undefined,
200+
history: [{
201+
modificationDate: date,
202+
}],
203+
};
204+
if (req.query.baddateresponse === 'functionNotExists') {
205+
result.creationDate = new ObjectID();
206+
}
207+
else if (req.query.baddateresponse === 'functionBadFormat') {
208+
result.creationDate = new BadDate();
209+
}
210+
else {
211+
result.creationDate = date;
212+
}
213+
res.json(result);
214+
});
215+
app.post([`${app.basePath}/users`], (req, res) => {
216+
if (typeof req.body.id !== 'string') {
217+
throw new Error("Should NOT be deserialized to ObjectId object");
218+
}
219+
if (typeof req.body.creationDate !== 'string') {
220+
throw new Error("Should NTO be deserialized to Date object");
221+
}
222+
if (typeof req.body.creationDateTime !== 'string') {
223+
throw new Error("Should NOT be deserialized to Date object");
224+
}
225+
req.body.id = new ObjectID(req.body.id);
226+
req.body.creationDateTime = new Date(req.body.creationDateTime);
227+
// We let creationDate as String and it should also work (either in Date Object ou String 'date' format)
228+
res.json(req.body);
229+
});
230+
app.use((err, req, res, next) => {
231+
console.error(err)
232+
res.status(err.status ?? 500).json({
233+
message: err.message,
234+
code: err.status ?? 500,
235+
});
236+
});
237+
},
238+
false,
239+
);
240+
return app
241+
});
242+
243+
after(() => {
244+
app.server.close();
245+
});
246+
247+
it('should control BAD id format and throw an error', async () =>
248+
request(app)
249+
.get(`${app.basePath}/users/1234`)
250+
.expect(400)
251+
.then((r) => {
252+
expect(r.body.message).to.equal('request.params.id should match pattern "^[0-9a-fA-F]{24}$"');
253+
}));
254+
255+
it('should control GOOD id format and get a response in expected format', async () =>
256+
request(app)
257+
.get(`${app.basePath}/users/5fdefd13a6640bb5fb5fa925`)
258+
.expect(200)
259+
.then((r) => {
260+
expect(r.body.id).to.equal('5fdefd13a6640bb5fb5fa925');
261+
expect(r.body.creationDate).to.equal('2020-12-20');
262+
expect(r.body.creationDateTime).to.equal("2020-12-20T07:28:19.213Z");
263+
expect(r.body.history[0].modificationDate).to.equal("2020-12-20");
264+
}));
265+
266+
it('should POST also works with deserialize on request then serialize en response', async () =>
267+
request(app)
268+
.post(`${app.basePath}/users`)
269+
.send({
270+
id: '5fdefd13a6640bb5fb5fa925',
271+
creationDateTime: '2020-12-20T07:28:19.213Z',
272+
creationDate: '2020-12-20'
273+
})
274+
.set('Content-Type', 'application/json')
275+
.expect(200)
276+
.then((r) => {
277+
expect(r.body.id).to.equal('5fdefd13a6640bb5fb5fa925');
278+
expect(r.body.creationDate).to.equal('2020-12-20');
279+
expect(r.body.creationDateTime).to.equal("2020-12-20T07:28:19.213Z");
280+
}));
281+
282+
it('should POST throw error on invalid schema ObjectId', async () =>
283+
request(app)
284+
.post(`${app.basePath}/users`)
285+
.send({
286+
id: '5fdefd13a6640bb5fb5fa',
287+
creationDateTime: '2020-12-20T07:28:19.213Z',
288+
creationDate: '2020-12-20'
289+
})
290+
.set('Content-Type', 'application/json')
291+
.expect(400)
292+
.then((r) => {
293+
expect(r.body.message).to.equal('request.body.id should match pattern "^[0-9a-fA-F]{24}$"');
294+
}));
295+
296+
it('should POST throw error on invalid schema Date', async () =>
297+
request(app)
298+
.post(`${app.basePath}/users`)
299+
.send({
300+
id: '5fdefd13a6640bb5fb5fa925',
301+
creationDateTime: '2020-12-20T07:28:19.213Z',
302+
creationDate: '2020-1f-20'
303+
})
304+
.set('Content-Type', 'application/json')
305+
.expect(400)
306+
.then((r) => {
307+
expect(r.body.message).to.equal('request.body.creationDate should match format "date"');
308+
}));
309+
310+
it('should throw error 500 on invalid object type instead of Date expected', async () =>
311+
request(app)
312+
.get(`${app.basePath}/users/5fdefd13a6640bb5fb5fa925`)
313+
.query({ baddateresponse: 'functionNotExists' })
314+
.expect(500)
315+
.then((r) => {
316+
console.log(r);
317+
expect(r.body.message).to.equal('d.toISOString is not a function');
318+
}));
319+
320+
/*
321+
FIXME Manage format validation after serialize ? I can serialize using a working serialize method but that respond a bad format
322+
it('should throw error 500 on an object that serialize to a bad string format', async () =>
323+
324+
request(app)
325+
.get(`${app.basePath}/users/5fdefd13a6640bb5fb5fa925`)
326+
.query({baddateresponse : 'functionBadFormat'})
327+
.expect(200)
328+
.then((r) => {
329+
console.log(r.body);
330+
expect(r.body.message).to.equal('Something saying that date is not date-time format');
331+
}));
332+
333+
*/
334+
335+
});

0 commit comments

Comments
 (0)