> I have no specific error handling for the given problem
then pass it on and decide what to do with it at the system boundary
in the db:
fun getUser(uuid: UUID) : Either<Error, User>
middle layers: pass around the either, you can map, flatmap etc on it to chain it with other computations there
then in the resource layer
return user .fold({ error -> when(error) { is DbError -> HttpResponse.InternalServerError() is UserNotFoundError -> HttpResponse.NotFound } }, { user -> HttpResponse.ok(user) })
Then, at every layer, each method explicitly says in the method signature what it returns. There’s no need to look around each and every line of every method in every layer, or in the framework, or some global exception handler, to figure out what will happen. Developers can tell from a glance at the resource method what the endpoint will return for each outcome, in context.
Things like being unable to communicate with the DB or not finding a user are not exceptional, they're entirely expectable when you're calling a db to look for a user and should be modeled accordingly.