Skip to content

Commit 52429c5

Browse files
committed
Allow to get the generated request AJV object in order to use it out of an OpenAPI and express usage (websocket...)
cdimascio#683
1 parent c0983c6 commit 52429c5

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

src/index.ts

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
// export default openapiValidator;
1818
export const resolvers = res;
1919
export const middleware = openapiValidator;
20+
export const ajv = ajvInstances;
2021
export const error = {
2122
InternalServerError,
2223
UnsupportedMediaType,
@@ -43,3 +44,16 @@ function openapiValidator(options: OpenApiValidatorOpts) {
4344
}).load(),
4445
);
4546
}
47+
48+
function ajvInstances(options: OpenApiValidatorOpts) {
49+
const oav = new OpenApiValidator(options);
50+
exports.middleware._oav = oav;
51+
52+
return oav.installAjv(
53+
new OpenApiSpecLoader({
54+
apiDoc: cloneDeep(options.apiSpec),
55+
validateApiSpec: options.validateApiSpec,
56+
$refParser: options.$refParser,
57+
}).load(),
58+
);
59+
}

src/middlewares/openapi.request.validator.ts

+4
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ export class RequestValidator {
227227
}
228228
}
229229
}
230+
231+
public getAJV () : Ajv {
232+
return this.ajv;
233+
}
230234
}
231235

232236
class Validator {

src/openapi.validator.ts

+22
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { OperationHandlerOptions } from './framework/types';
2020
import { defaultSerDes } from './framework/base.serdes';
2121
import { SchemaPreprocessor } from './middlewares/parsers/schema.preprocessor';
2222
import { AjvOptions } from './framework/ajv/options';
23+
import { Ajv } from 'ajv';
2324

2425
export {
2526
OpenApiValidatorOpts,
@@ -90,6 +91,27 @@ export class OpenApiValidator {
9091
this.ajvOpts = new AjvOptions(options);
9192
}
9293

94+
installAjv(spec: Promise<Spec>): Promise<Ajv> {
95+
return spec
96+
.then((spec) => {
97+
const apiDoc = spec.apiDoc;
98+
const ajvOpts = this.ajvOpts.preprocessor;
99+
const resOpts = this.options.validateResponses as ValidateRequestOpts;
100+
const sp = new SchemaPreprocessor(
101+
apiDoc,
102+
ajvOpts,
103+
resOpts,
104+
).preProcess();
105+
/*return {
106+
context: new OpenApiContext(spec, this.options.ignorePaths, this.options.ignoreUndocumented),
107+
responseApiDoc: sp.apiDocRes,
108+
error: null,
109+
};*/
110+
return new middlewares.RequestValidator(apiDoc, this.ajvOpts.request).getAJV();
111+
});
112+
}
113+
114+
93115
installMiddleware(spec: Promise<Spec>): OpenApiRequestHandler[] {
94116
const middlewares: OpenApiRequestHandler[] = [];
95117
const pContext = spec

test/ajv.return.spec.ts

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import * as path from 'path';
2+
import { expect } from 'chai';
3+
4+
import { date, dateTime } from '../src/framework/base.serdes';
5+
import * as OpenApiValidator from '../src';
6+
import { Ajv } from 'ajv';
7+
8+
const apiSpecPath = path.join('test', 'resources', 'serdes.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+
describe('ajv.return', () => {
23+
let ajv : Ajv = null;
24+
25+
before(async () => {
26+
ajv = await OpenApiValidator.ajv({
27+
apiSpec: apiSpecPath,
28+
validateRequests: {
29+
coerceTypes: true
30+
},
31+
validateResponses: {
32+
coerceTypes: true
33+
},
34+
serDes: [
35+
date,
36+
dateTime,
37+
{
38+
format: "mongo-objectid",
39+
deserialize: (s) => new ObjectID(s),
40+
serialize: (o) => o.toString(),
41+
},
42+
],
43+
unknownFormats: ['string-list'],
44+
});
45+
});
46+
47+
it('should control BAD id format and throw an error', async () => {
48+
class ReqClass {
49+
id: string|ObjectID
50+
}
51+
52+
const req : ReqClass = {
53+
id : '507f191e810c19729de860ea',
54+
}
55+
56+
ajv.validate(
57+
{
58+
type: 'object',
59+
properties: {
60+
id: {
61+
$ref: '#/components/schemas/ObjectId',
62+
},
63+
},
64+
required: ['token'],
65+
additionalProperties: false,
66+
},
67+
req
68+
);
69+
expect(req.id instanceof ObjectID).to.be.true;
70+
});
71+
});
72+
73+
74+

0 commit comments

Comments
 (0)