POLISH-1: gridify emits canonical '='; localize litter InvalidParentGender 400 (ApiError body) + de strings

This commit is contained in:
2026-06-06 07:55:59 +02:00
parent e87d0aafea
commit 55a72bfe12
4 changed files with 41 additions and 6 deletions

View File

@@ -13,15 +13,27 @@ export class ApiError extends Error {
readonly status: number | null
/** The request path that failed (for diagnostics/logging). */
readonly path?: string
/** Parsed error response body, if any (e.g. { code, ... } for 400s). */
readonly body?: unknown
constructor(message: string, status: number | null, path?: string) {
constructor(message: string, status: number | null, path?: string, body?: unknown) {
super(message)
this.name = 'ApiError'
this.status = status
this.path = path
this.body = body
}
}
/** Read a `code` field off a parsed ApiError body, if present. */
export function errorCode(err: unknown): string | null {
if (err instanceof ApiError && err.body && typeof err.body === 'object' && 'code' in err.body) {
const code = (err.body as { code: unknown }).code
return typeof code === 'string' ? code : null
}
return null
}
function errorMessageFor(status: number): string {
if (status === 404) return de.api.errors.notFound
if (status >= 500) return de.api.errors.server
@@ -40,7 +52,14 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
}
if (!response.ok) {
throw new ApiError(errorMessageFor(response.status), response.status, path)
// Best-effort parse of a JSON error body (e.g. { code: "InvalidParentGender" }).
let body: unknown
try {
body = await response.clone().json()
} catch {
body = undefined
}
throw new ApiError(errorMessageFor(response.status), response.status, path, body)
}
if (response.status === 204) {

View File

@@ -47,8 +47,10 @@ export function condition(c: FilterCondition): string {
const suffix = c.caseInsensitive === false ? '' : '/i'
return `${c.field}=*${escaped}*${suffix}`
}
// Gridify's equals operator is a single '='; callers use '==' semantically.
const op = c.op === '==' ? '=' : c.op
const suffix = c.caseInsensitive ? '/i' : ''
return `${c.field}${c.op}${escaped}${suffix}`
return `${c.field}${op}${escaped}${suffix}`
}
/** Join conditions with AND (comma). Falsy/empty conditions are dropped. */