-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How can I catch errors by their status code? #382
Comments
Here's how I wrote it: import * as Router from 'koa-router';
import * as httpStatusCodes from 'http-status-codes';
import { AxiosError } from 'axios';
import * as createHttpError from 'http-errors';
import * as Boom from '@hapi/boom';
import { assertUnreachable } from '../agnosticUtilities/assertUnreachable';
function isAxiosError(input: unknown & object): input is AxiosError {
const innocentUntilGuilty = input as Partial<AxiosError>;
return !!innocentUntilGuilty.stack && !!innocentUntilGuilty.code && typeof innocentUntilGuilty.code === 'string';
}
function isHttpError(input: unknown & object): input is createHttpError.HttpError {
const innocentUntilGuilty = input as Partial<createHttpError.HttpError>;
return (
!!innocentUntilGuilty.stack &&
!!innocentUntilGuilty.statusCode &&
typeof innocentUntilGuilty.statusCode === 'number'
);
}
const grabStatusCodeFromError = (error: Error | AxiosError | createHttpError.HttpError | Boom): number | undefined => {
// ######################
// IMPORTANT NOTE: Boom must be first in the check since some libraries (like tsoa) automatically set the ".code" to 500 if there wasn't one.
// So if .code is the first thing you check, then you'd never arrive at .output.statusCode
// ######################
if (Boom.isBoom(error)) {
return error.output.statusCode;
}
if (isHttpError(error)) {
return error.statusCode;
}
if (isAxiosError(error)) {
return error.code ? parseInt(error.code) : undefined;
}
if (error instanceof Error) {
return undefined; // since standard errors don't have http status codes
} else {
return assertUnreachable(error, 'We got some kind of error that we do not have a handler for');
}
};
export const errorResponder: Router.IMiddleware = async (ctx, next) => {
try {
await next();
} catch (err) {
const expose = process.env.EXPOSE_STACK;
// tslint:disable-next-line: no-unsafe-any
const statusCode = grabStatusCodeFromError(err) || httpStatusCodes.INTERNAL_SERVER_ERROR;
ctx.status = statusCode;
ctx.body = {
// tslint:disable-next-line: no-unsafe-any
message: err.message || 'An error occurred',
// tslint:disable-next-line: no-unsafe-any
correlationId: ctx.state.correlationId,
// tslint:disable-next-line: no-unsafe-any
stack: expose ? err.stack : undefined,
};
}
}; And then in your
Note: just remember to add the middleware before the routes are added (as I describe in #381) k, so here's how you would throw a 404 now that you have this middleware in place that supports Boom errors: @Get('{id}')
public async getThingById(id: string, @Request() request: koa.Request): Promise<IThing> {
const theThing = myDb.findById(id);
if(!theThing){
throw Boom.notFound(`Could not find a resource by id ${id}`)
}
return theThing;
} |
What about with Express? In express I get: If I try to throw a Boom error after registering an express-boom handler with the server. |
Please take that question to either StackOverflow or to the Boom github repo. It’s not tsoa related. |
ok np. |
Figured out another thing that I'd like to share with the community.
Goal: You want to try/catch the results of your entire app, and if the error that's thrown has an http status code, then you want to return that to the user so they have more information. This is a common pattern due to the use of Boom
The text was updated successfully, but these errors were encountered: