4
votes

I was wondering what folks think would be a good way of handling errors in a REST-style api written in Clojure, using the Ring library.

One approach taken by Paul Umbers in his Clojure RESTful API tutorial is to let exceptions happen naturally and allow them to bubble all the way up to a piece of middleware specialized in turning exceptions to specific HTTP status codes.

Basically, DB constraints will throw their own specific errors (e.g PSQLException), model validators will throw another type, all under the code 400 umbrella. Unknown exceptions will be caught by the generic Exception handler and return the 500 code.

A few thoughts:

  • Can we do better? Is this the wrong design for some specific reason?
  • Many will claim that handling the generic Exception type is bad practice. Can such an argument be made here as well?

Thanks!

1

1 Answers

1
votes

I'm by no means an expert in this particular area, but since no one else has weighed in, I'll give my two cents.

The solution you linked to seems like a reasonable approach to me. Given a small amount of cooperation between your handlers and your exception middleware, you could also tag your exceptions with additional information that might be useful when rendering an error response, without the actual details of the error handling creeping into your application logic.

So to your first question: it's possible you could tailor your system more to a given specific use case, but as a general-purpose error handling scheme, this seems pretty good. There's nothing about it that jumps out at me as straight-up "wrong".

To your second question: It's bad practice to catch the generic Exception type when you know you're looking for a more specific one, because you want to avoid conflating expected and unexpected errors. If you know there's a possibility of a MissingResourceException when you do a bundle lookup, you wouldn't want your exception handler for that to accidentally bury a NullPointerException bubbling up from an actual bug in your code.

In this case, though, I would argue that catching the generic Exception type is exactly the right thing to be doing. Rather than handling specific conditions like a MissingResourceException, the goal of this top-level handler is to catch anything that your application logic doesn't and convert it into error information that's meaningful to the client of your API. It's a sort of last line of defense between your implementation and its consumer at the other end.