Using Koa v2.7.0 and TypeScript v3.3.1
My "errorHandler" middleware function being exported like this
export const clientErrorHandler = () => {
return async (ctx: Context, next: NextFunction) => {
try{
await next();
}
catch (err){
if(err instanceof HTTPClientError){
console.warn(err);
ctx.status = err.statusCode;
ctx.body = err.message;
ctx.app.emit('error', err, ctx);
}
}
}
}
My logic which handles the attachment of the middleware on the given Koa app looks like this:
export const handleErrors = (app: Koa) => {
const serverErrHandler = serverErrorHandler();
serverErrHandler._name = 'serverErrorHandler';
app.use(serverErrHandler)
}
The reason why I'm trying to create this property is due to this Koa documentation (see link below) which states that we can give middleware functions a _name property so that when we run the program with DEBUG=koa*
set, this middleware function will be able to have a name that shows up in the console.
Since JavaScript does not allow defining function names at runtime, you can also set a middleware's name as ._name. This is useful when you don't have control of a middleware's name. For example:
const path = require('path'); const serve = require('koa-static');
const publicFiles = serve(path.join(__dirname, 'public'));
publicFiles._name = 'static /public';
app.use(publicFiles);
Source of the above snippet: https://github.com/koajs/koa/blob/master/docs/guide.md#debugging-koa
However, when trying this, since I'm using TypeScript, it does not like it that I'm trying to set a property on this anonymous function.
[ts] Property '_name' does not exist on type '(ctx: Context, next: NextFunction) => Promise'.
I was hoping to determine the best way to go about enabling myself to be able to add this little _name
property to this anonymous function so that I could have solid debugging logs.
As I was writing this out I ended up finding two possible solutions.
The one that I'm going with, is to simply not use an anonymous function, so there is no need to modify a _name
property on my middleware function. After re-reading the koa documentation I think a key phrase I looked over was
"for middleware that you don't have control over"
My middleware function definition now looks like this:
export const clientErrorHandler = () => {
let clientErrHandler = async (ctx: Context, next: NextFunction) => {
try{
await next();
}
catch (err){
if(err instanceof HTTPClientError){
console.warn(err);
ctx.status = err.statusCode;
ctx.body = err.message;
ctx.app.emit('error', err, ctx);
}
}
}
return clientErrHandler;
}
Now, if this hypothetically were the case where you didn't have control over a 3rd party middleware function name AND you were using TypeScript, I found that this stack overflow solution helps in that scenario: https://stackoverflow.com/a/18640025
Using that that stackoverflow's suggestion, one could define an interface and do a type assertion with the anonymous function to produce a result that would let the caller typescript code set the _name
property on the returned function without complaining that no such property existed.
Just to demonstrate what this looks like:
Even though I'm demonstrating this on the code that you technically wouldn't have access to modify I assume you could do a type assertion on the caller side as well and then modify the _name
property after that.
interface MiddlewareFunction { (ctx: Context, next: NextFunction ): Promise<void>; _name: string; }
export const serverErrorHandler = () => {
return <MiddlewareFunction> async function (ctx: Context, next: NextFunction){
try {
await next();
}
catch (err) {
if(process.env.NODE_ENV === 'production'){
ctx.status = 500;
ctx.body = 'Internal Server Error';
}
else {
ctx.status = err.status;
ctx.body = err.stack;
ctx.app.emit('error', err, ctx);
}
}
}
}
Same code as in the question:
export const handleErrors = (app: Koa) => {
const serverErrHandler = serverErrorHandler();
serverErrHandler._name = 'serverErrorHandler';
app.use(serverErrHandler)
}
EDIT: You can also just change from arrow function back to a normal named javascript function in the return.
export const serverErrorHandler = () => {
return async function serverErrorHandler (ctx: Context, next: NextFunction){
try {
await next();
}
catch (err) {
if(process.env.NODE_ENV === 'production'){
ctx.status = 500;
ctx.body = 'Internal Server Error';
}
else {
ctx.status = err.status;
ctx.body = err.stack;
ctx.app.emit('error', err, ctx);
}
}
}
}