Files
dyolink/backend/src/common/errors/validation-exception.factory.ts
Admin 80167c622c bugfix: appointment hours now use the client timezone on UTC servers.
Logical API errors throw stable codes so users see translated messages instead of a generic bad request.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 01:43:50 +03:30

74 lines
2.2 KiB
TypeScript

import { HttpException, HttpStatus } from '@nestjs/common';
import type { ValidationError } from 'class-validator';
import { AppException } from './app.exception';
import { ErrorCode, type ErrorCodeValue, type ValidationErrorDetail } from './error-codes';
const KNOWN_VALIDATION_CODES = new Set<string>(Object.values(ErrorCode));
function isKnownValidationCode(value: string): value is ErrorCodeValue {
return KNOWN_VALIDATION_CODES.has(value);
}
function constraintToCode(constraintKey: string, message: string): ErrorCodeValue {
if (isKnownValidationCode(message)) {
return message;
}
switch (constraintKey) {
case 'isEmail':
return ErrorCode.VALIDATION_EMAIL_INVALID;
case 'minLength':
return ErrorCode.VALIDATION_PASSWORD_TOO_SHORT;
case 'isEnum':
return ErrorCode.VALIDATION_ORGANIZATION_TYPE_INVALID;
case 'matches':
case 'isDateString':
case 'isUuid':
case 'isInt':
case 'isBoolean':
case 'isArray':
return ErrorCode.VALIDATION_INVALID_REQUEST;
case 'isIn':
return ErrorCode.VALIDATION_LANGUAGE_INVALID;
case 'whitelistValidation':
return ErrorCode.VALIDATION_INVALID_REQUEST;
default:
return ErrorCode.VALIDATION_FIELD_REQUIRED;
}
}
function flattenValidationErrors(
errors: ValidationError[],
parentPath = '',
): ValidationErrorDetail[] {
const details: ValidationErrorDetail[] = [];
for (const error of errors) {
const field = parentPath ? `${parentPath}.${error.property}` : error.property;
if (error.constraints) {
const [constraintKey, message] = Object.entries(error.constraints)[0];
details.push({
field,
code: constraintToCode(constraintKey, message),
});
}
if (error.children?.length) {
details.push(...flattenValidationErrors(error.children, field));
}
}
return details;
}
export function validationExceptionFactory(errors: ValidationError[]): HttpException {
const details = flattenValidationErrors(errors);
if (details.length === 0) {
return new AppException(ErrorCode.VALIDATION_FAILED, HttpStatus.BAD_REQUEST);
}
return new AppException(ErrorCode.VALIDATION_FAILED, HttpStatus.BAD_REQUEST, details);
}