feat: internationalize API error responses by locale
Add shared error codes with zh/en/ms messages, coded app exceptions, and locale-aware global filter. Frontends send X-Locale so error text matches the active UI language. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
45
apps/api/src/shared/common/app-error.ts
Normal file
45
apps/api/src/shared/common/app-error.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
ForbiddenException,
|
||||
NotFoundException,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import type { ApiErrorCode, ApiErrorParams } from '@thebet365/shared';
|
||||
|
||||
function body(code: ApiErrorCode, params?: ApiErrorParams) {
|
||||
const clean = params
|
||||
? Object.fromEntries(
|
||||
Object.entries(params)
|
||||
.filter(([, v]) => v !== undefined && v !== null)
|
||||
.map(([k, v]) => [k, String(v)]),
|
||||
)
|
||||
: undefined;
|
||||
return { code, params: clean };
|
||||
}
|
||||
|
||||
export function appBadRequest(code: ApiErrorCode, params?: ApiErrorParams) {
|
||||
return new BadRequestException(body(code, params));
|
||||
}
|
||||
|
||||
export function appNotFound(code: ApiErrorCode, params?: ApiErrorParams) {
|
||||
return new NotFoundException(body(code, params));
|
||||
}
|
||||
|
||||
export function appForbidden(code: ApiErrorCode, params?: ApiErrorParams) {
|
||||
return new ForbiddenException(body(code, params));
|
||||
}
|
||||
|
||||
export function appUnauthorized(code: ApiErrorCode, params?: ApiErrorParams) {
|
||||
return new UnauthorizedException(body(code, params));
|
||||
}
|
||||
|
||||
export function isCodedExceptionResponse(
|
||||
res: unknown,
|
||||
): res is { code: ApiErrorCode; params?: ApiErrorParams } {
|
||||
return (
|
||||
typeof res === 'object' &&
|
||||
res !== null &&
|
||||
'code' in res &&
|
||||
typeof (res as { code: unknown }).code === 'string'
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user