@dvsa/appdev-api-common 0.4.1 → 0.4.3
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/package.json +48 -51
- package/validation/request-body.js +11 -13
- package/validation/validation-error.d.ts +14 -0
- package/validation/validation-error.js +28 -0
package/package.json
CHANGED
|
@@ -1,53 +1,50 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"lint-staged": {
|
|
51
|
-
"*.{js,ts,mjs,css,md,ts,json}": "npm run lint:fix -- --no-errors-on-unmatched"
|
|
52
|
-
}
|
|
2
|
+
"name": "@dvsa/appdev-api-common",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"keywords": ["dvsa", "nodejs", "typescript"],
|
|
5
|
+
"author": "DVSA",
|
|
6
|
+
"description": "Utils library for common API functionality",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"directory": "dist",
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"localLink": "npm run clean && npm version patch && npm run build && cp package.json dist && cd dist && npm link",
|
|
13
|
+
"clean": "rimraf coverage dist",
|
|
14
|
+
"clean:temp": "rimraf auth api",
|
|
15
|
+
"lint": "biome check src",
|
|
16
|
+
"lint:fix": "npm run lint -- --write",
|
|
17
|
+
"build": "npm run clean && tsc",
|
|
18
|
+
"build:package": "npm run build",
|
|
19
|
+
"test": "jest",
|
|
20
|
+
"test:coverage": "jest --coverage",
|
|
21
|
+
"prepublishOnly": "npm run build:package && cp -r ./dist/* . && rm -rf ./dist",
|
|
22
|
+
"postpublish": "git clean -fd && npm run clean:temp",
|
|
23
|
+
"gitSecrets": "git secrets --scan . && git log -p -- . | scanrepo"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"ajv": "^8.17.1",
|
|
27
|
+
"ajv-formats": "^3.0.1",
|
|
28
|
+
"dayjs": "^1.11.13",
|
|
29
|
+
"jose": "^5.9.6"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@biomejs/biome": "1.9.3",
|
|
33
|
+
"@dvsa/biome-config": "0.3.0",
|
|
34
|
+
"@types/aws-lambda": "^8.10.145",
|
|
35
|
+
"@types/express": "^5.0.0",
|
|
36
|
+
"@types/jest": "^29.5.14",
|
|
37
|
+
"@types/node": "^20.14.8",
|
|
38
|
+
"husky": "^9.1.7",
|
|
39
|
+
"jest": "^29.7.0",
|
|
40
|
+
"lint-staged": "^15.2.10",
|
|
41
|
+
"rimraf": "^6.0.1",
|
|
42
|
+
"routing-controllers": "^0.11.2",
|
|
43
|
+
"ts-jest": "^29.2.5",
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
|
+
"typescript": "^5.5.2"
|
|
46
|
+
},
|
|
47
|
+
"lint-staged": {
|
|
48
|
+
"*.{js,ts,mjs,css,md,ts,json}": "npm run lint:fix -- --no-errors-on-unmatched"
|
|
49
|
+
}
|
|
53
50
|
}
|
|
@@ -5,8 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ValidateRequestBody = ValidateRequestBody;
|
|
7
7
|
const ajv_1 = __importDefault(require("ajv"));
|
|
8
|
+
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
8
9
|
const http_status_codes_1 = require("../api/http-status-codes");
|
|
10
|
+
const validation_error_1 = require("./validation-error");
|
|
9
11
|
const ajv = new ajv_1.default({ removeAdditional: true, allErrors: true });
|
|
12
|
+
(0, ajv_formats_1.default)(ajv);
|
|
10
13
|
ajv.addKeyword("tsEnumNames");
|
|
11
14
|
/**
|
|
12
15
|
* Decorator tp validate an express request body against a specified schema
|
|
@@ -15,15 +18,15 @@ ajv.addKeyword("tsEnumNames");
|
|
|
15
18
|
* - isArray: whether the body is expected to be an array
|
|
16
19
|
* - errorDetails: whether to return detailed error messages (Note: errors are logged regardless of this setting)
|
|
17
20
|
*/
|
|
18
|
-
function ValidateRequestBody(schema, opts = { isArray: false, errorDetails:
|
|
21
|
+
function ValidateRequestBody(schema, opts = { isArray: false, errorDetails: true }) {
|
|
19
22
|
return (_target, _propertyKey, descriptor) => {
|
|
20
23
|
const originalMethod = descriptor.value;
|
|
21
|
-
|
|
24
|
+
// biome-ignore lint/suspicious/noExplicitAny: tuples should be any in this instance
|
|
25
|
+
descriptor.value = async function (...args) {
|
|
26
|
+
const [body] = args;
|
|
22
27
|
// just to be safe, check the bodies existence before attempting to validate it
|
|
23
28
|
if (!body) {
|
|
24
|
-
|
|
25
|
-
.status(http_status_codes_1.HttpStatus.BAD_REQUEST)
|
|
26
|
-
.json({ message: "No request body detected" });
|
|
29
|
+
throw new validation_error_1.ValidationError(http_status_codes_1.HttpStatus.BAD_REQUEST, "No request body detected");
|
|
27
30
|
}
|
|
28
31
|
const payload = Buffer.isBuffer(body)
|
|
29
32
|
? JSON.parse(body.toString("utf-8"))
|
|
@@ -37,17 +40,12 @@ function ValidateRequestBody(schema, opts = { isArray: false, errorDetails: fals
|
|
|
37
40
|
const isValid = validateFunction(payload);
|
|
38
41
|
// if an error exists, then return a 400 with details
|
|
39
42
|
if (!isValid) {
|
|
43
|
+
console.error("Validation failed on body:", JSON.stringify(body));
|
|
40
44
|
console.error(validateFunction.errors);
|
|
41
|
-
|
|
42
|
-
message: "Validation error",
|
|
43
|
-
};
|
|
44
|
-
if (opts?.errorDetails) {
|
|
45
|
-
Object.assign(response, { errors: validateFunction.errors });
|
|
46
|
-
}
|
|
47
|
-
return res.status(http_status_codes_1.HttpStatus.BAD_REQUEST).json(response);
|
|
45
|
+
throw new validation_error_1.ValidationError(http_status_codes_1.HttpStatus.BAD_REQUEST, "Validation failed", opts?.errorDetails ? validateFunction.errors : null);
|
|
48
46
|
}
|
|
49
47
|
// proceed with attached method if schema is valid
|
|
50
|
-
return originalMethod.apply(this,
|
|
48
|
+
return originalMethod.apply(this, args);
|
|
51
49
|
};
|
|
52
50
|
};
|
|
53
51
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HttpStatus } from "../api/http-status-codes";
|
|
2
|
+
export declare class ValidationError extends Error {
|
|
3
|
+
private readonly statusCode;
|
|
4
|
+
private readonly details;
|
|
5
|
+
constructor(statusCode?: HttpStatus, message?: string, details?: unknown | null);
|
|
6
|
+
toJSON(): {
|
|
7
|
+
error: {
|
|
8
|
+
name: string;
|
|
9
|
+
message: string;
|
|
10
|
+
details: unknown;
|
|
11
|
+
statusCode: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidationError = void 0;
|
|
4
|
+
const http_status_codes_1 = require("../api/http-status-codes");
|
|
5
|
+
class ValidationError extends Error {
|
|
6
|
+
statusCode;
|
|
7
|
+
details;
|
|
8
|
+
constructor(statusCode = http_status_codes_1.HttpStatus.BAD_REQUEST, message = "Validation failed", details = null) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.statusCode = statusCode;
|
|
11
|
+
this.details = details;
|
|
12
|
+
this.name = "ValidationError";
|
|
13
|
+
if (Error.captureStackTrace) {
|
|
14
|
+
Error.captureStackTrace(this, ValidationError);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
toJSON() {
|
|
18
|
+
return {
|
|
19
|
+
error: {
|
|
20
|
+
name: this.name,
|
|
21
|
+
message: this.message,
|
|
22
|
+
details: this.details,
|
|
23
|
+
statusCode: this.statusCode,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.ValidationError = ValidationError;
|