77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
/**
|
|
* The envelope every endpoint answers with, the error codes it carries, the
|
|
* shape of a paginated list, and {@link Wire}, which maps a type to what JSON
|
|
* makes of it.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
/** The error codes an {@link APIError} carries, by name. */
|
|
export const APIErrorCode = {
|
|
/** The request is malformed or not allowed in the current state. */
|
|
BAD_REQUEST: "BAD_REQUEST",
|
|
/** What the request names doesn't exist, or the caller may not see it. */
|
|
NOT_FOUND: "NOT_FOUND",
|
|
/** The server failed. */
|
|
SERVER_ERROR: "SERVER_ERROR",
|
|
/** A remote site took too long to answer. */
|
|
TIMEOUT: "TIMEOUT",
|
|
/** The caller isn't signed in, or may not do this. */
|
|
UNAUTHORIZED: "UNAUTHORIZED",
|
|
/** The request body failed validation. */
|
|
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
} as const;
|
|
|
|
/** One of the {@link APIErrorCode} values. */
|
|
export type APIErrorCode = typeof APIErrorCode[keyof typeof APIErrorCode];
|
|
|
|
/** What went wrong, in a failed response. */
|
|
export interface APIError {
|
|
/** The kind of failure. */
|
|
code: APIErrorCode;
|
|
/** A human-readable explanation. */
|
|
message: string;
|
|
}
|
|
|
|
/** A successful response, carrying its payload. */
|
|
export interface APISuccess<T> {
|
|
/** Always true. */
|
|
success: true;
|
|
/** The payload. */
|
|
data: T;
|
|
/** Never set on success. */
|
|
error?: never;
|
|
}
|
|
|
|
/** A failed response, carrying its error. */
|
|
export interface APIFailure {
|
|
/** Always false. */
|
|
success: false;
|
|
/** Never set on failure. */
|
|
data?: never;
|
|
/** What went wrong. */
|
|
error: APIError;
|
|
}
|
|
|
|
/** What every endpoint answers with, narrowed by `success`. */
|
|
export type APIResponse<T> = APISuccess<T> | APIFailure;
|
|
|
|
/** One page of a list. */
|
|
export interface PaginatedData<T> {
|
|
/** The page's items. */
|
|
items: T[];
|
|
/** Whether another page follows. */
|
|
hasMore: boolean;
|
|
/** The whole list's size — only where it's shown (search results). */
|
|
total?: number;
|
|
}
|
|
|
|
/**
|
|
* `T` as it arrives over JSON (HTTP, the socket, localStorage): every Date is
|
|
* an ISO string.
|
|
*/
|
|
export type Wire<T> = T extends Date ? string
|
|
: T extends readonly (infer U)[] ? Wire<U>[]
|
|
: T extends object ? { [K in keyof T]: Wire<T[K]> }
|
|
: T;
|