Error Handling
All errors thrown within Routes/Hooks will be caught and added to the internalErrors
Array in the CallContext.request
object.
When there is an Error in a route/hook
the rest of the hooks/routes
in the execution path
are not executed. Hooks
can still get executed if runOnError
is set to true.
mion does not include any logger by default so applications should typically include a "log" hook to handle and log errors.
RpcError
mion provides the RpcError
class to help with the creation and serialization of errors, response status code etc... It also automatically generates an uuid
when RouterOptions.autoGenerateErrorId
is enabled. This is useful so the error can be traced between the client and the server.
Routes and Hooks should throw/return RpcErrors
specifying status code, error name, and publicMessage in case we want to return a message to the client.
RpcErrors get anonymized when returned to the client, this means stack trace and messages are never sent to the public. To return a message to the client use the publicMessage
property when creating the error.
RpcErrors can be serialized and unlike regular Errors in JS, the message
gets also serialized so it can be properly logged as JSON.
autoGenerateErrorId
is disabled by default.Throwing RpcError
export const getPet = route(async (ctx, id: string): Promise<Pet | RpcError> => {
try {
const pet = await myApp.db.getPet(id);
if (!pet) {
// Only statusCode and publicMessage will be returned in the response.body
const statusCode = StatusCodes.BAD_REQUEST;
const publicMessage = `Pet with id ${id} can't be found`;
// either return or throw are allowed
return new RpcError({statusCode, publicMessage});
}
return pet;
} catch (dbError) {
const statusCode = StatusCodes.INTERNAL_SERVER_ERROR;
const publicMessage = `Cant fetch data.`;
/*
* Only statusCode and publicMessage will be returned in the response.body.
*
* Full RpcError containing dbError message and stacktrace will be added
* to ctx.request.internalErrors, so it can be logged or managed after
*/
return new RpcError({statusCode, publicMessage, originalError: dbError as Error});
}
}) satisfies Route;
Throwing Error
If a generic Error
is thrown/returned by any route/hook, then a generic 500, Unknown RpcError
is generated by mion and returned to the client.
export const alwaysError = route((): void => {
throw new Error('will generate a 500 error with an "Unknown Error" message');
}) satisfies Route;
Type Reference
RpcError
export interface RpcErrorParams {
/** id of the error. */
id?: number | string;
/** response status code */
statusCode: number;
/** the message that will be returned in the response */
publicMessage?: string;
/**
* the error message, it is private and wont be returned in the response.
* If not defined, it is assigned from originalError.message or publicMessage.
*/
message?: string;
/** options data related to the error, ie validation data */
errorData?: unknown;
/** original error used to create the RpcError */
originalError?: Error;
/** name of the error, if not defined it is assigned from status code */
name?: string;
}
AnonymRpcError
export interface AnonymRpcError extends RpcErrorParams {
// when a RpcError gets anonymized the publicMessage becomes the message.
message: string;
statusCode: number;
name: string;
}