I’m putting together a ping API to check the health of a system. I want whatever mess comes back when things are broken - not specific errors.
What’s a reasonable way to specify that? (I didn’t stumble into a general catch-all by reading the docs or the code.)
val ping: Endpoint[Unit, Unit, Throwable, String, Any] = endpont
.get
.in("_ping")
.out(statusCode(StatusCode.Ok))
.out(stringBody)
.errorOut(something to convert any problems into a Throwable or a Left or just blast out the exception)
the endpoint description - where you specify what should be the shape of the response
the actual server logic which throws exceptions or returns errors
Of course, 1. and 2. need to be compatible
If you have code which throws exceptions and want to get a 500 Internal Server Error when this happens, then just using infallibleEndpoint and letting the exceptions be thrown is fine - there’s an interceptor down the line which handles that. You might want to combine that with logging to capture the stack trace (might be enabled by default, depending on the server interpreter used).
If you want to return the error in the response - using .errorOut(stringBody) is the most general solution. You might want to map this to Throwables: .errorOut(stringBody.map[Throwable](v => new RuntimeException(v))(_.getMessage)). This handles 1. For 2., you can then use .serverLogicRecoverErrors or .handleRecoverErrors to get exception handling at the level of the server logic (not through an interceptor).
If you’d share some more details (e.g. your effect system, server interpreter, more specific use-case) we can work on a more complete example.
This particular endpoint is a ping; it will reply - with “pong” in all services. It’s very simple and I expect it to work unless something is misconfigured or just missing.
What’s more interesting is when it does not work. That’s when I want all the information about what went wrong - to log and alert someone in ops.
From tests (using http4s but I want to stay uncommitted a little longer) I get useful information via exceptions if I include just one .errorOut() variant. I’d rather have none, but if I leave out the .errorOut() then ping() always returns Unit when it is broken, and I lose all the information about what broke.
Is there a way to specify .errorOut() to burp out exceptions without specifying any variants ?
Is that what .infallibleEndpoint does? (Does infallible mean that everything broken throws an exception or everything broken returns Unit?)
Ok, so, first of all, if there’s any kind of uncaught exception (or a failed effect), then it should be logged (see Http4sDefaultServerLog). That’s totally independent of whatever the errorOut specification is. You’ll also get a 500 response, see CustomiseInterceptors and ExceptionHandler.
The error outputs description the shape of the response in case of “expected” errors (e.g. a validation error). The type of the error output dictates the result you need to return from your server logic - an Either[E, O], where E is the shape of the error output. If your server logic responds with such an error, it won’t be logged anywhere as an error, as it’s treated as a successfully handled request and successful response, although mapping to a non-200 status code.
infallibleEndpointis an endpoint where there are no expected errors. It behaves the same in face of exceptions.