41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
/**
|
|
* Lets any layer fail a request with an HTTP status, which the error middleware
|
|
* turns into the response.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { APIErrorCode } from "../../shared/api.ts";
|
|
|
|
/** Passed to an {@link APIException}; any other status is a type error. */
|
|
export type APIStatus = 400 | 401 | 403 | 404 | 409 | 429 | 500 | 502;
|
|
|
|
const CODES: Record<APIStatus, APIErrorCode> = {
|
|
400: APIErrorCode.BAD_REQUEST,
|
|
401: APIErrorCode.UNAUTHORIZED,
|
|
403: APIErrorCode.FORBIDDEN,
|
|
404: APIErrorCode.NOT_FOUND,
|
|
409: APIErrorCode.CONFLICT,
|
|
429: APIErrorCode.RATE_LIMITED,
|
|
500: APIErrorCode.SERVER_ERROR,
|
|
502: APIErrorCode.BAD_GATEWAY,
|
|
};
|
|
|
|
/**
|
|
* Thrown by a route, a service or a remote fetch to answer the request with an
|
|
* error. The error middleware sends it as an `APIFailure`, message included,
|
|
* so the message must be fit for the user. Use 401 for a caller who isn't
|
|
* signed in, 403 for one who is but may not, and 404 rather than 403 when the
|
|
* caller mustn't learn that the thing exists.
|
|
*/
|
|
export class APIException extends Error {
|
|
readonly code: APIErrorCode;
|
|
readonly status: APIStatus;
|
|
|
|
constructor(status: APIStatus, message: string) {
|
|
super(message);
|
|
this.status = status;
|
|
this.code = CODES[status];
|
|
}
|
|
}
|