koa: Way to set headers on HttpErrors
Currently, the default error handler in koa checks for the status property on errors and sets the status accordingly. However, many errors in the HTTP spec are defined with required or recommended headers to be send along with the status. For example, 405 Method Not Allowed should always be sent with an Allow header, a 503 Service Unavailable with a Retry After.
Currently, it is not possible to set this. You could write your own error handler that checks a headers property on the error object, but third party middleware can’t rely on that. As a result, middleware modules on npm (like koa-router etc.) have to set status and headers on the context response manually instead of throwing an error, which means it is not possible to catch them and therefor destroys one of the best features of koa - error handling with try / catch.
It would be nice if the koa error handler would check for the existence of a headers property on the object and set the headers in that hash (with normalized casing). http-errors already supports passing a properties hash in the constructor, so it could look like this:
throw new HttpError(405, {headers: {'Allow': 'GET, POST'}})
throw new HttpError(503, {headers: {'Retry-After': 60}})
This would then allow middlewares from npm to actually throw errors that can be catched to add some additional custom text etc. Thoughts?
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 30 (30 by maintainers)
why just ‘don’t remove’ the headers already set ? because with this solution when you want keep a header set by module X from module Y you have to reference errors set in modules X in modules Y? or maybe a flag to say i want remove all header on error, and not i want keep some headers?
it is a bad thing if the middleware automatically responds with 401 if I always wanted to respond with an uniform JSON error response in my API (Google APIs do this, for example). This is especially true if you have the requirement to follow HATEOS, so you always need to provide links in the response body. Just an example. Then it would be nice to do this:
this is all pseudocode of course. The point is, it doesn’t work, because jwtMiddleware responds directly with 401 - because if it throws, it can’t add additional info aka headers. Sure jwt could implement a
errorResponseTransformeroption or something like that, but at that point we would be basically passing middleware functions to factories, wtf xDIn your example, middleware could technically modify
Retry-After, but the only function that knows what value makes sense is the middleware that threw the 503. 503 might be a bad example, but equally only the authorization middleware knows thatWWW-Authenticateshould beBasicorDigest, only the router knows that thatAllowneeds to beGET, PUT.In the end, there are no exceptions in javascript, only errors. And one of the great things about javascript is that we can attach custom stuff to objects. Do I understand you correctly that you think thrown errors should only be for stuff that seriously went wrong and have nothing to do with HTTP, so basically only 500? We should remove http-errors then 😉
But I get your thoughts… somewhere we need to draw the line. Next we allow a
bodyproperty on the error… And koa3 middleware functions get only passed the request and either call next,return new KoaResponse({status, body, headers})orthrow new KoaErrorResponse({status, body, headers})… It’s just where should this line be drawn? 1) Keep errors out of HTTP responses? 2) Allow status and message (current behaviour)? 3) allow headers too? Imo either 1 or 3.