@loopback/example-validation-app 7.0.2 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/__tests__/acceptance/validate-discriminator.acceptance.d.ts +1 -0
- package/dist/__tests__/acceptance/validate-discriminator.acceptance.js +78 -0
- package/dist/__tests__/acceptance/validate-discriminator.acceptance.js.map +1 -0
- package/dist/application.js +5 -0
- package/dist/application.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +1 -0
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/pet.controller.d.ts +5 -0
- package/dist/controllers/pet.controller.js +36 -0
- package/dist/controllers/pet.controller.js.map +1 -0
- package/dist/middleware/validation-error.middleware.js +2 -1
- package/dist/middleware/validation-error.middleware.js.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/pet.model.d.ts +23 -0
- package/dist/models/pet.model.js +112 -0
- package/dist/models/pet.model.js.map +1 -0
- package/package.json +12 -12
- package/src/__tests__/acceptance/validate-discriminator.acceptance.ts +89 -0
- package/src/application.ts +7 -1
- package/src/controllers/index.ts +1 -0
- package/src/controllers/pet.controller.ts +30 -0
- package/src/middleware/validation-error.middleware.ts +4 -1
- package/src/models/index.ts +1 -0
- package/src/models/pet.model.ts +86 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [7.0.4](https://github.com/loopbackio/loopback-next/compare/@loopback/example-validation-app@7.0.3...@loopback/example-validation-app@7.0.4) (2025-08-11)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @loopback/example-validation-app
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [7.0.3](https://github.com/loopbackio/loopback-next/compare/@loopback/example-validation-app@7.0.2...@loopback/example-validation-app@7.0.3) (2025-07-15)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* adding tests and comments illustrating the discriminator bug issue ([82a33cc](https://github.com/loopbackio/loopback-next/commit/82a33cc840266c1707f73a1b3e71a0224e456f26))
|
|
20
|
+
* illustrate the discriminator bug and fix in loopback rest request-body-validator ([9fa3593](https://github.com/loopbackio/loopback-next/commit/9fa35934b067ae804e3cd19c06b9d290571da798))
|
|
21
|
+
* removal of comments and implementation of bug fix ([f0da7dd](https://github.com/loopbackio/loopback-next/commit/f0da7dd6fdf119a4ce0e083997c4d5bdad3a0b9c))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
6
27
|
## [7.0.2](https://github.com/loopbackio/loopback-next/compare/@loopback/example-validation-app@7.0.1...@loopback/example-validation-app@7.0.2) (2025-06-12)
|
|
7
28
|
|
|
8
29
|
**Note:** Version bump only for package @loopback/example-validation-app
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/example-validation-app
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const testlab_1 = require("@loopback/testlab");
|
|
8
|
+
const test_helper_1 = require("./test-helper");
|
|
9
|
+
const validCat = {
|
|
10
|
+
name: 'Kitty',
|
|
11
|
+
weight: 5,
|
|
12
|
+
kind: 'Cat',
|
|
13
|
+
animalProperties: {
|
|
14
|
+
color: 'grey',
|
|
15
|
+
whiskerLength: 2,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const validDog = {
|
|
19
|
+
name: 'Rex',
|
|
20
|
+
weight: 5,
|
|
21
|
+
kind: 'Dog',
|
|
22
|
+
animalProperties: {
|
|
23
|
+
breed: 'poodle',
|
|
24
|
+
barkVolume: 5,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
describe('validate properties based on discriminated schemas', () => {
|
|
28
|
+
let client;
|
|
29
|
+
let app;
|
|
30
|
+
before(givenAClient);
|
|
31
|
+
after(async () => {
|
|
32
|
+
await app.stop();
|
|
33
|
+
});
|
|
34
|
+
async function givenAClient() {
|
|
35
|
+
({ app, client } = await (0, test_helper_1.setupApplication)());
|
|
36
|
+
}
|
|
37
|
+
it('should pass with valid cat properties', async () => {
|
|
38
|
+
await client.post('/pets').send(validCat).expect(200);
|
|
39
|
+
});
|
|
40
|
+
it('should pass with valid dog properties', async () => {
|
|
41
|
+
await client.post('/pets').send(validDog).expect(200);
|
|
42
|
+
});
|
|
43
|
+
it('should fail with error indicating invalid barkVolume type', async () => {
|
|
44
|
+
const invalidDog = { ...validDog };
|
|
45
|
+
invalidDog.animalProperties.barkVolume = 'loud';
|
|
46
|
+
const response = await client.post('/pets').send(invalidDog).expect(422);
|
|
47
|
+
(0, testlab_1.expect)(response.body.error.details.length).to.equal(1);
|
|
48
|
+
(0, testlab_1.expect)(response.body.error.details[0].message).to.equal('must be number');
|
|
49
|
+
(0, testlab_1.expect)(response.body.error.details).to.deepEqual([
|
|
50
|
+
{
|
|
51
|
+
code: 'type',
|
|
52
|
+
info: {
|
|
53
|
+
type: 'number',
|
|
54
|
+
},
|
|
55
|
+
message: 'must be number',
|
|
56
|
+
path: '/animalProperties/barkVolume',
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
it('should fail with error indicating invalid whiskerLength type', async () => {
|
|
61
|
+
const invalidCat = { ...validCat };
|
|
62
|
+
invalidCat.animalProperties.whiskerLength = 'long';
|
|
63
|
+
const response = await client.post('/pets').send(invalidCat).expect(422);
|
|
64
|
+
(0, testlab_1.expect)(response.body.error.details.length).to.equal(1);
|
|
65
|
+
(0, testlab_1.expect)(response.body.error.details[0].message).to.equal('must be number');
|
|
66
|
+
(0, testlab_1.expect)(response.body.error.details).to.deepEqual([
|
|
67
|
+
{
|
|
68
|
+
code: 'type',
|
|
69
|
+
info: {
|
|
70
|
+
type: 'number',
|
|
71
|
+
},
|
|
72
|
+
message: 'must be number',
|
|
73
|
+
path: '/animalProperties/whiskerLength',
|
|
74
|
+
},
|
|
75
|
+
]);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=validate-discriminator.acceptance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-discriminator.acceptance.js","sourceRoot":"","sources":["../../../src/__tests__/acceptance/validate-discriminator.acceptance.ts"],"names":[],"mappings":"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"}
|
package/dist/application.js
CHANGED
|
@@ -23,6 +23,11 @@ class ValidationApplication extends (0, boot_1.BootMixin)((0, service_proxy_1.Se
|
|
|
23
23
|
this.sequence(sequence_1.MySequence);
|
|
24
24
|
// Set up default home page
|
|
25
25
|
this.static('/', path_1.default.join(__dirname, '../public'));
|
|
26
|
+
this.bind(rest_1.RestBindings.REQUEST_BODY_PARSER_OPTIONS).to({
|
|
27
|
+
validation: {
|
|
28
|
+
discriminator: true,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
26
31
|
// Customize @loopback/rest-explorer configuration here
|
|
27
32
|
this.configure(rest_explorer_1.RestExplorerBindings.COMPONENT).to({
|
|
28
33
|
path: '/explorer',
|
package/dist/application.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application.js","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAAyC;AACzC,yCAAyE;AACzE,qDAAqD;AACrD,
|
|
1
|
+
{"version":3,"file":"application.js","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAAyC;AACzC,yCAAyE;AACzE,qDAAqD;AACrD,yCAA6D;AAC7D,2DAGiC;AACjC,2DAAqD;AACrD,wDAAwB;AACxB,0FAA2F;AAC3F,yCAAsC;AAItC,MAAa,qBAAsB,SAAQ,IAAA,gBAAS,EAClD,IAAA,4BAAY,EAAC,IAAA,4BAAe,EAAC,sBAAe,CAAC,CAAC,CAC/C;IACC,YAAY,UAA6B,EAAE;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,GAAG,CAAC,IAAA,6BAAsB,EAAC,+DAAiC,CAAC,CAAC,CAAC;QAEpE,6BAA6B;QAC7B,IAAI,CAAC,QAAQ,CAAC,qBAAU,CAAC,CAAC;QAE1B,2BAA2B;QAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,mBAAY,CAAC,2BAA2B,CAAC,CAAC,EAAE,CAAC;YACrD,UAAU,EAAE;gBACV,aAAa,EAAE,IAAI;aACpB;SACF,CAAC,CAAC;QAEH,uDAAuD;QACvD,IAAI,CAAC,SAAS,CAAC,oCAAoB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YAChD,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,qCAAqB,CAAC,CAAC;QAEtC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,mDAAmD;QACnD,IAAI,CAAC,WAAW,GAAG;YACjB,WAAW,EAAE;gBACX,8CAA8C;gBAC9C,IAAI,EAAE,CAAC,aAAa,CAAC;gBACrB,UAAU,EAAE,CAAC,gBAAgB,CAAC;gBAC9B,MAAM,EAAE,IAAI;aACb;SACF,CAAC;IACJ,CAAC;CACF;AArCD,sDAqCC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;AAEhE,mEAAyC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;AAEhE,mEAAyC;AACzC,2DAAiC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/example-validation-app
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PetController = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const rest_1 = require("@loopback/rest");
|
|
10
|
+
const models_1 = require("../models");
|
|
11
|
+
class PetController {
|
|
12
|
+
constructor() { }
|
|
13
|
+
async create(request) {
|
|
14
|
+
return request;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.PetController = PetController;
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, rest_1.post)('/pets'),
|
|
20
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
21
|
+
content: {
|
|
22
|
+
'application/json': {
|
|
23
|
+
schema: {
|
|
24
|
+
discriminator: {
|
|
25
|
+
propertyName: 'kind',
|
|
26
|
+
},
|
|
27
|
+
oneOf: [{ 'x-ts-type': models_1.Cat }, { 'x-ts-type': models_1.Dog }],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
})),
|
|
32
|
+
tslib_1.__metadata("design:type", Function),
|
|
33
|
+
tslib_1.__metadata("design:paramtypes", [models_1.Pet]),
|
|
34
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
35
|
+
], PetController.prototype, "create", null);
|
|
36
|
+
//# sourceMappingURL=pet.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pet.controller.js","sourceRoot":"","sources":["../../src/controllers/pet.controller.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAAiD;AACjD,sCAAwC;AAExC,MAAa,aAAa;IACxB,gBAAe,CAAC;IAGV,AAAN,KAAK,CAAC,MAAM,CAaV,OAAY;QAEZ,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AArBD,sCAqBC;AAjBO;IADL,IAAA,WAAI,EAAC,OAAO,CAAC;IAEX,mBAAA,IAAA,kBAAW,EAAC;QACX,OAAO,EAAE;YACP,kBAAkB,EAAE;gBAClB,MAAM,EAAE;oBACN,aAAa,EAAE;wBACb,YAAY,EAAE,MAAM;qBACrB;oBACD,KAAK,EAAE,CAAC,EAAC,WAAW,EAAE,YAAG,EAAC,EAAE,EAAC,WAAW,EAAE,YAAG,EAAC,CAAC;iBAChD;aACF;SACF;KACF,CAAC,CAAA;;6CACO,YAAG;;2CAGb"}
|
|
@@ -34,7 +34,8 @@ let ValidationErrorMiddlewareProvider = class ValidationErrorMiddlewareProvider
|
|
|
34
34
|
handleError(context, err) {
|
|
35
35
|
var _a;
|
|
36
36
|
// 2. customize error for particular endpoint
|
|
37
|
-
if (context.request.url === '/coffee-shops'
|
|
37
|
+
if (context.request.url === '/coffee-shops' ||
|
|
38
|
+
context.request.url === '/pets') {
|
|
38
39
|
// if this is a validation error from the PATCH method, customize it
|
|
39
40
|
// for other validation errors, the default AJV error object will be sent
|
|
40
41
|
if (err.statusCode === 422 && context.request.method === 'PATCH') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-error.middleware.js","sourceRoot":"","sources":["../../src/middleware/validation-error.middleware.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAA4D;AAC5D,yCAUwB;AASjB,IAAM,iCAAiC,GAAvC,MAAM,iCAAiC;IAC5C,YAEY,QAAkB,EAElB,kBAAuC;QAFvC,aAAQ,GAAR,QAAQ,CAAU;QAElB,uBAAkB,GAAlB,kBAAkB,CAAqB;IAChD,CAAC;IAEJ,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAe,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACjD,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;gBAC5B,OAAO,MAAM,CAAC;aACf;YAAC,OAAO,GAAG,EAAE;gBACZ,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aACnC;QACH,CAAC,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,WAAW,CACT,OAA0B,EAC1B,GAAyB;;QAEzB,6CAA6C;QAC7C,
|
|
1
|
+
{"version":3,"file":"validation-error.middleware.js","sourceRoot":"","sources":["../../src/middleware/validation-error.middleware.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAA4D;AAC5D,yCAUwB;AASjB,IAAM,iCAAiC,GAAvC,MAAM,iCAAiC;IAC5C,YAEY,QAAkB,EAElB,kBAAuC;QAFvC,aAAQ,GAAR,QAAQ,CAAU;QAElB,uBAAkB,GAAlB,kBAAkB,CAAqB;IAChD,CAAC;IAEJ,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAe,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACjD,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;gBAC5B,OAAO,MAAM,CAAC;aACf;YAAC,OAAO,GAAG,EAAE;gBACZ,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aACnC;QACH,CAAC,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,WAAW,CACT,OAA0B,EAC1B,GAAyB;;QAEzB,6CAA6C;QAC7C,IACE,OAAO,CAAC,OAAO,CAAC,GAAG,KAAK,eAAe;YACvC,OAAO,CAAC,OAAO,CAAC,GAAG,KAAK,OAAO,EAC/B;YACA,oEAAoE;YACpE,yEAAyE;YACzE,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE;gBAChE,MAAM,iBAAiB,GAAG,wCAAwC,CAAC;gBAEnE,IAAI,eAAe,GAAG,EAAE,CAAC;gBACzB,IAAI,MAAA,IAAI,CAAC,kBAAkB,0CAAE,KAAK,EAAE;oBAClC,eAAe,GAAG,EAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAC,CAAC;iBACtC;gBAED,mDAAmD;gBACnD,0CAA0C;gBAC1C,MAAM,SAAS,GAAG;oBAChB,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,iBAAiB;oBAC1B,UAAU,EAAE,yCAAyC;oBACrD,IAAI,EAAE,mBAAmB;oBACzB,GAAG,eAAe;iBACnB,CAAC;gBAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAE7C,gEAAgE;gBAChE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBAEpD,wBAAwB;gBACxB,OAAO,OAAO,CAAC,QAAQ,CAAC;aACzB;iBAAM;gBACL,MAAM,GAAG,CAAC;aACX;SACF;IACH,CAAC;CACF,CAAA;AAnEY,8EAAiC;4CAAjC,iCAAiC;IAP7C,IAAA,iBAAU,EACT,IAAA,mBAAY,EAAC;QACX,KAAK,EAAE,iBAAiB;QACxB,cAAc,EAAE,2BAAoB,CAAC,aAAa;QAClD,gBAAgB,EAAE,2BAAoB,CAAC,IAAI;KAC5C,CAAC,CACH;IAGI,mBAAA,IAAA,aAAM,EAAC,mBAAY,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;IAE9C,mBAAA,IAAA,aAAM,EAAC,mBAAY,CAAC,oBAAoB,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA;;GAJnD,iCAAiC,CAmE7C"}
|
package/dist/models/index.d.ts
CHANGED
package/dist/models/index.js
CHANGED
package/dist/models/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;AAEhE,8DAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,gDAAgD;AAChD,+CAA+C;AAC/C,gEAAgE;;;AAEhE,8DAAoC;AACpC,sDAA4B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Model } from '@loopback/repository';
|
|
2
|
+
export declare class CatProperties extends Model {
|
|
3
|
+
color: string;
|
|
4
|
+
whiskerLength: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class DogProperties extends Model {
|
|
7
|
+
breed: string;
|
|
8
|
+
barkVolume: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class Pet extends Model {
|
|
11
|
+
name: string;
|
|
12
|
+
weight?: number;
|
|
13
|
+
kind: string;
|
|
14
|
+
animalProperties: CatProperties | DogProperties;
|
|
15
|
+
}
|
|
16
|
+
export declare class Dog extends Pet {
|
|
17
|
+
kind: string;
|
|
18
|
+
animalProperties: DogProperties;
|
|
19
|
+
}
|
|
20
|
+
export declare class Cat extends Pet {
|
|
21
|
+
kind: string;
|
|
22
|
+
animalProperties: CatProperties;
|
|
23
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Cat = exports.Dog = exports.Pet = exports.DogProperties = exports.CatProperties = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const repository_1 = require("@loopback/repository");
|
|
6
|
+
let CatProperties = class CatProperties extends repository_1.Model {
|
|
7
|
+
};
|
|
8
|
+
exports.CatProperties = CatProperties;
|
|
9
|
+
tslib_1.__decorate([
|
|
10
|
+
(0, repository_1.property)({
|
|
11
|
+
type: String,
|
|
12
|
+
required: true,
|
|
13
|
+
}),
|
|
14
|
+
tslib_1.__metadata("design:type", String)
|
|
15
|
+
], CatProperties.prototype, "color", void 0);
|
|
16
|
+
tslib_1.__decorate([
|
|
17
|
+
(0, repository_1.property)({
|
|
18
|
+
type: Number,
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
tslib_1.__metadata("design:type", Number)
|
|
22
|
+
], CatProperties.prototype, "whiskerLength", void 0);
|
|
23
|
+
exports.CatProperties = CatProperties = tslib_1.__decorate([
|
|
24
|
+
(0, repository_1.model)()
|
|
25
|
+
], CatProperties);
|
|
26
|
+
let DogProperties = class DogProperties extends repository_1.Model {
|
|
27
|
+
};
|
|
28
|
+
exports.DogProperties = DogProperties;
|
|
29
|
+
tslib_1.__decorate([
|
|
30
|
+
(0, repository_1.property)({
|
|
31
|
+
type: String,
|
|
32
|
+
required: true,
|
|
33
|
+
}),
|
|
34
|
+
tslib_1.__metadata("design:type", String)
|
|
35
|
+
], DogProperties.prototype, "breed", void 0);
|
|
36
|
+
tslib_1.__decorate([
|
|
37
|
+
(0, repository_1.property)({
|
|
38
|
+
type: Number,
|
|
39
|
+
required: true,
|
|
40
|
+
}),
|
|
41
|
+
tslib_1.__metadata("design:type", Number)
|
|
42
|
+
], DogProperties.prototype, "barkVolume", void 0);
|
|
43
|
+
exports.DogProperties = DogProperties = tslib_1.__decorate([
|
|
44
|
+
(0, repository_1.model)()
|
|
45
|
+
], DogProperties);
|
|
46
|
+
let Pet = class Pet extends repository_1.Model {
|
|
47
|
+
};
|
|
48
|
+
exports.Pet = Pet;
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, repository_1.property)({
|
|
51
|
+
type: String,
|
|
52
|
+
required: true,
|
|
53
|
+
}),
|
|
54
|
+
tslib_1.__metadata("design:type", String)
|
|
55
|
+
], Pet.prototype, "name", void 0);
|
|
56
|
+
tslib_1.__decorate([
|
|
57
|
+
(0, repository_1.property)({
|
|
58
|
+
type: Number,
|
|
59
|
+
required: false,
|
|
60
|
+
}),
|
|
61
|
+
tslib_1.__metadata("design:type", Number)
|
|
62
|
+
], Pet.prototype, "weight", void 0);
|
|
63
|
+
exports.Pet = Pet = tslib_1.__decorate([
|
|
64
|
+
(0, repository_1.model)()
|
|
65
|
+
], Pet);
|
|
66
|
+
let Dog = class Dog extends Pet {
|
|
67
|
+
};
|
|
68
|
+
exports.Dog = Dog;
|
|
69
|
+
tslib_1.__decorate([
|
|
70
|
+
(0, repository_1.property)({
|
|
71
|
+
type: String,
|
|
72
|
+
jsonSchema: {
|
|
73
|
+
enum: ['Dog'],
|
|
74
|
+
},
|
|
75
|
+
required: true,
|
|
76
|
+
}),
|
|
77
|
+
tslib_1.__metadata("design:type", String)
|
|
78
|
+
], Dog.prototype, "kind", void 0);
|
|
79
|
+
tslib_1.__decorate([
|
|
80
|
+
(0, repository_1.property)({
|
|
81
|
+
type: DogProperties,
|
|
82
|
+
required: true,
|
|
83
|
+
}),
|
|
84
|
+
tslib_1.__metadata("design:type", DogProperties)
|
|
85
|
+
], Dog.prototype, "animalProperties", void 0);
|
|
86
|
+
exports.Dog = Dog = tslib_1.__decorate([
|
|
87
|
+
(0, repository_1.model)()
|
|
88
|
+
], Dog);
|
|
89
|
+
let Cat = class Cat extends Pet {
|
|
90
|
+
};
|
|
91
|
+
exports.Cat = Cat;
|
|
92
|
+
tslib_1.__decorate([
|
|
93
|
+
(0, repository_1.property)({
|
|
94
|
+
type: String,
|
|
95
|
+
jsonSchema: {
|
|
96
|
+
enum: ['Cat'],
|
|
97
|
+
},
|
|
98
|
+
required: true,
|
|
99
|
+
}),
|
|
100
|
+
tslib_1.__metadata("design:type", String)
|
|
101
|
+
], Cat.prototype, "kind", void 0);
|
|
102
|
+
tslib_1.__decorate([
|
|
103
|
+
(0, repository_1.property)({
|
|
104
|
+
type: CatProperties,
|
|
105
|
+
required: true,
|
|
106
|
+
}),
|
|
107
|
+
tslib_1.__metadata("design:type", CatProperties)
|
|
108
|
+
], Cat.prototype, "animalProperties", void 0);
|
|
109
|
+
exports.Cat = Cat = tslib_1.__decorate([
|
|
110
|
+
(0, repository_1.model)()
|
|
111
|
+
], Cat);
|
|
112
|
+
//# sourceMappingURL=pet.model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pet.model.js","sourceRoot":"","sources":["../../src/models/pet.model.ts"],"names":[],"mappings":";;;;AAAA,qDAA4D;AAGrD,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,kBAAK;CAYvC,CAAA;AAZY,sCAAa;AAKxB;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC;;4CACY;AAMd;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC;;oDACoB;wBAXX,aAAa;IADzB,IAAA,kBAAK,GAAE;GACK,aAAa,CAYzB;AAGM,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,kBAAK;CAYvC,CAAA;AAZY,sCAAa;AAKxB;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC;;4CACY;AAMd;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC;;iDACiB;wBAXR,aAAa;IADzB,IAAA,kBAAK,GAAE;GACK,aAAa,CAYzB;AAGM,IAAM,GAAG,GAAT,MAAM,GAAI,SAAQ,kBAAK;CAgB7B,CAAA;AAhBY,kBAAG;AAKd;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC;;iCACW;AAMb;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,KAAK;KAChB,CAAC;;mCACc;cAXL,GAAG;IADf,IAAA,kBAAK,GAAE;GACK,GAAG,CAgBf;AAGM,IAAM,GAAG,GAAT,MAAM,GAAI,SAAQ,GAAG;CAe3B,CAAA;AAfY,kBAAG;AAQd;IAPC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE;YACV,IAAI,EAAE,CAAC,KAAK,CAAC;SACd;QACD,QAAQ,EAAE,IAAI;KACf,CAAC;;iCACW;AAMb;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,IAAI;KACf,CAAC;sCACgB,aAAa;6CAAC;cAdrB,GAAG;IADf,IAAA,kBAAK,GAAE;GACK,GAAG,CAef;AAGM,IAAM,GAAG,GAAT,MAAM,GAAI,SAAQ,GAAG;CAe3B,CAAA;AAfY,kBAAG;AAQd;IAPC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE;YACV,IAAI,EAAE,CAAC,KAAK,CAAC;SACd;QACD,QAAQ,EAAE,IAAI;KACf,CAAC;;iCACW;AAMb;IAJC,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,IAAI;KACf,CAAC;sCACgB,aAAa;6CAAC;cAdrB,GAAG;IADf,IAAA,kBAAK,GAAE;GACK,GAAG,CAef"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopback/example-validation-app",
|
|
3
3
|
"description": "An example demonstrating how to add validation in a LoopBack 4 application",
|
|
4
|
-
"version": "7.0.
|
|
4
|
+
"version": "7.0.4",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"loopback",
|
|
7
7
|
"LoopBack",
|
|
@@ -50,23 +50,23 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@loopback/boot": "^8.0.
|
|
54
|
-
"@loopback/core": "^7.0.
|
|
55
|
-
"@loopback/repository": "^8.0.
|
|
56
|
-
"@loopback/rest": "^15.0.
|
|
57
|
-
"@loopback/rest-explorer": "^8.0.
|
|
58
|
-
"@loopback/service-proxy": "^8.0.
|
|
59
|
-
"strong-error-handler": "^5.0.
|
|
53
|
+
"@loopback/boot": "^8.0.4",
|
|
54
|
+
"@loopback/core": "^7.0.3",
|
|
55
|
+
"@loopback/repository": "^8.0.3",
|
|
56
|
+
"@loopback/rest": "^15.0.4",
|
|
57
|
+
"@loopback/rest-explorer": "^8.0.4",
|
|
58
|
+
"@loopback/service-proxy": "^8.0.3",
|
|
59
|
+
"strong-error-handler": "^5.0.22",
|
|
60
60
|
"tslib": "^2.8.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@loopback/build": "^12.0.
|
|
64
|
-
"@loopback/eslint-config": "^16.0.
|
|
65
|
-
"@loopback/testlab": "^8.0.
|
|
63
|
+
"@loopback/build": "^12.0.3",
|
|
64
|
+
"@loopback/eslint-config": "^16.0.1",
|
|
65
|
+
"@loopback/testlab": "^8.0.3",
|
|
66
66
|
"@types/node": "^16.18.126",
|
|
67
67
|
"eslint": "^8.57.1",
|
|
68
68
|
"source-map-support": "^0.5.21",
|
|
69
69
|
"typescript": "~5.2.2"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "292b33022f1d9eb85ded26e7b07a3d7a47d3b2e8"
|
|
72
72
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/example-validation-app
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {Client, expect} from '@loopback/testlab';
|
|
7
|
+
import {ValidationApplication} from '../..';
|
|
8
|
+
import {setupApplication} from './test-helper';
|
|
9
|
+
|
|
10
|
+
const validCat = {
|
|
11
|
+
name: 'Kitty',
|
|
12
|
+
weight: 5,
|
|
13
|
+
kind: 'Cat',
|
|
14
|
+
animalProperties: {
|
|
15
|
+
color: 'grey',
|
|
16
|
+
whiskerLength: 2,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const validDog = {
|
|
21
|
+
name: 'Rex',
|
|
22
|
+
weight: 5,
|
|
23
|
+
kind: 'Dog',
|
|
24
|
+
animalProperties: {
|
|
25
|
+
breed: 'poodle',
|
|
26
|
+
barkVolume: 5,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('validate properties based on discriminated schemas', () => {
|
|
31
|
+
let client: Client;
|
|
32
|
+
let app: ValidationApplication;
|
|
33
|
+
|
|
34
|
+
before(givenAClient);
|
|
35
|
+
|
|
36
|
+
after(async () => {
|
|
37
|
+
await app.stop();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
async function givenAClient() {
|
|
41
|
+
({app, client} = await setupApplication());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
it('should pass with valid cat properties', async () => {
|
|
45
|
+
await client.post('/pets').send(validCat).expect(200);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should pass with valid dog properties', async () => {
|
|
49
|
+
await client.post('/pets').send(validDog).expect(200);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should fail with error indicating invalid barkVolume type', async () => {
|
|
53
|
+
const invalidDog = {...validDog};
|
|
54
|
+
invalidDog.animalProperties.barkVolume = 'loud' as unknown as number;
|
|
55
|
+
const response = await client.post('/pets').send(invalidDog).expect(422);
|
|
56
|
+
|
|
57
|
+
expect(response.body.error.details.length).to.equal(1);
|
|
58
|
+
expect(response.body.error.details[0].message).to.equal('must be number');
|
|
59
|
+
expect(response.body.error.details).to.deepEqual([
|
|
60
|
+
{
|
|
61
|
+
code: 'type',
|
|
62
|
+
info: {
|
|
63
|
+
type: 'number',
|
|
64
|
+
},
|
|
65
|
+
message: 'must be number',
|
|
66
|
+
path: '/animalProperties/barkVolume',
|
|
67
|
+
},
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should fail with error indicating invalid whiskerLength type', async () => {
|
|
72
|
+
const invalidCat = {...validCat};
|
|
73
|
+
invalidCat.animalProperties.whiskerLength = 'long' as unknown as number;
|
|
74
|
+
const response = await client.post('/pets').send(invalidCat).expect(422);
|
|
75
|
+
|
|
76
|
+
expect(response.body.error.details.length).to.equal(1);
|
|
77
|
+
expect(response.body.error.details[0].message).to.equal('must be number');
|
|
78
|
+
expect(response.body.error.details).to.deepEqual([
|
|
79
|
+
{
|
|
80
|
+
code: 'type',
|
|
81
|
+
info: {
|
|
82
|
+
type: 'number',
|
|
83
|
+
},
|
|
84
|
+
message: 'must be number',
|
|
85
|
+
path: '/animalProperties/whiskerLength',
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
});
|
|
89
|
+
});
|
package/src/application.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import {BootMixin} from '@loopback/boot';
|
|
7
7
|
import {ApplicationConfig, createBindingFromClass} from '@loopback/core';
|
|
8
8
|
import {RepositoryMixin} from '@loopback/repository';
|
|
9
|
-
import {RestApplication} from '@loopback/rest';
|
|
9
|
+
import {RestApplication, RestBindings} from '@loopback/rest';
|
|
10
10
|
import {
|
|
11
11
|
RestExplorerBindings,
|
|
12
12
|
RestExplorerComponent,
|
|
@@ -32,6 +32,12 @@ export class ValidationApplication extends BootMixin(
|
|
|
32
32
|
// Set up default home page
|
|
33
33
|
this.static('/', path.join(__dirname, '../public'));
|
|
34
34
|
|
|
35
|
+
this.bind(RestBindings.REQUEST_BODY_PARSER_OPTIONS).to({
|
|
36
|
+
validation: {
|
|
37
|
+
discriminator: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
35
41
|
// Customize @loopback/rest-explorer configuration here
|
|
36
42
|
this.configure(RestExplorerBindings.COMPONENT).to({
|
|
37
43
|
path: '/explorer',
|
package/src/controllers/index.ts
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/example-validation-app
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {post, requestBody} from '@loopback/rest';
|
|
7
|
+
import {Cat, Dog, Pet} from '../models';
|
|
8
|
+
|
|
9
|
+
export class PetController {
|
|
10
|
+
constructor() {}
|
|
11
|
+
|
|
12
|
+
@post('/pets')
|
|
13
|
+
async create(
|
|
14
|
+
@requestBody({
|
|
15
|
+
content: {
|
|
16
|
+
'application/json': {
|
|
17
|
+
schema: {
|
|
18
|
+
discriminator: {
|
|
19
|
+
propertyName: 'kind',
|
|
20
|
+
},
|
|
21
|
+
oneOf: [{'x-ts-type': Cat}, {'x-ts-type': Dog}],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
request: Pet,
|
|
27
|
+
): Promise<Pet> {
|
|
28
|
+
return request;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -54,7 +54,10 @@ export class ValidationErrorMiddlewareProvider implements Provider<Middleware> {
|
|
|
54
54
|
err: HttpErrors.HttpError,
|
|
55
55
|
): Response | undefined {
|
|
56
56
|
// 2. customize error for particular endpoint
|
|
57
|
-
if (
|
|
57
|
+
if (
|
|
58
|
+
context.request.url === '/coffee-shops' ||
|
|
59
|
+
context.request.url === '/pets'
|
|
60
|
+
) {
|
|
58
61
|
// if this is a validation error from the PATCH method, customize it
|
|
59
62
|
// for other validation errors, the default AJV error object will be sent
|
|
60
63
|
if (err.statusCode === 422 && context.request.method === 'PATCH') {
|
package/src/models/index.ts
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {Model, model, property} from '@loopback/repository';
|
|
2
|
+
|
|
3
|
+
@model()
|
|
4
|
+
export class CatProperties extends Model {
|
|
5
|
+
@property({
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
})
|
|
9
|
+
color: string;
|
|
10
|
+
|
|
11
|
+
@property({
|
|
12
|
+
type: Number,
|
|
13
|
+
required: true,
|
|
14
|
+
})
|
|
15
|
+
whiskerLength: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@model()
|
|
19
|
+
export class DogProperties extends Model {
|
|
20
|
+
@property({
|
|
21
|
+
type: String,
|
|
22
|
+
required: true,
|
|
23
|
+
})
|
|
24
|
+
breed: string;
|
|
25
|
+
|
|
26
|
+
@property({
|
|
27
|
+
type: Number,
|
|
28
|
+
required: true,
|
|
29
|
+
})
|
|
30
|
+
barkVolume: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@model()
|
|
34
|
+
export class Pet extends Model {
|
|
35
|
+
@property({
|
|
36
|
+
type: String,
|
|
37
|
+
required: true,
|
|
38
|
+
})
|
|
39
|
+
name: string;
|
|
40
|
+
|
|
41
|
+
@property({
|
|
42
|
+
type: Number,
|
|
43
|
+
required: false,
|
|
44
|
+
})
|
|
45
|
+
weight?: number;
|
|
46
|
+
|
|
47
|
+
kind: string;
|
|
48
|
+
|
|
49
|
+
animalProperties: CatProperties | DogProperties;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@model()
|
|
53
|
+
export class Dog extends Pet {
|
|
54
|
+
@property({
|
|
55
|
+
type: String,
|
|
56
|
+
jsonSchema: {
|
|
57
|
+
enum: ['Dog'],
|
|
58
|
+
},
|
|
59
|
+
required: true,
|
|
60
|
+
})
|
|
61
|
+
kind: string;
|
|
62
|
+
|
|
63
|
+
@property({
|
|
64
|
+
type: DogProperties,
|
|
65
|
+
required: true,
|
|
66
|
+
})
|
|
67
|
+
animalProperties: DogProperties;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@model()
|
|
71
|
+
export class Cat extends Pet {
|
|
72
|
+
@property({
|
|
73
|
+
type: String,
|
|
74
|
+
jsonSchema: {
|
|
75
|
+
enum: ['Cat'],
|
|
76
|
+
},
|
|
77
|
+
required: true,
|
|
78
|
+
})
|
|
79
|
+
kind: string;
|
|
80
|
+
|
|
81
|
+
@property({
|
|
82
|
+
type: CatProperties,
|
|
83
|
+
required: true,
|
|
84
|
+
})
|
|
85
|
+
animalProperties: CatProperties;
|
|
86
|
+
}
|