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