Files
client-web/src/api/types.ts
T

43 lines
1.4 KiB
TypeScript

import type { ApiFieldErrors } from '@/api/errorDetails'
export interface ApiEnvelope<T> {
code: string
message: string
data: T
requestId: string | null
traceId: string | null
timestamp: string
}
export type { ApiFieldErrors } from '@/api/errorDetails'
export class ApiError extends Error {
constructor(
message: string,
readonly code = 'NETWORK_ERROR',
readonly status?: number,
readonly fieldErrors?: ApiFieldErrors,
readonly traceId?: string | null,
readonly requestId?: string | null,
) {
super(message)
this.name = 'ApiError'
}
}
export function isApiEnvelope(value: unknown): value is ApiEnvelope<unknown> {
if (!value || typeof value !== 'object') return false
const record = value as Record<string, unknown>
return typeof record.code === 'string' && typeof record.message === 'string' && 'data' in record
}
// Security failures have no business data, unlike successful API responses.
export function isApiFailure(value: unknown): value is Omit<ApiEnvelope<never>, 'data'> {
if (!value || typeof value !== 'object') return false
const record = value as Record<string, unknown>
return typeof record.code === 'string' && record.code !== '200'
&& typeof record.message === 'string'
&& (record.requestId == null || typeof record.requestId === 'string')
&& (record.traceId == null || typeof record.traceId === 'string')
}