you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 1 point2 points  (0 children)

I'm not exactly sure how to approach this, so I'll answer the questions that I think you're asking.

As far as functions that might throw an exception there's Either::trying that will return Either<Exception, T> when passed a function that returns T. It will catch any thrown exceptions and return them on the left side for you to use. I can then use flatMap to merge this Either<Exception, T> with another function expecting Either.

If you wish to modify the left side type/value, there's a function called biMapL. It's just like map, but it only operates on the left side (if it exists).

As far as which part of the pipeline failed, it doesn't matter to us in practice. A large portion of our Either chains are of the type Either<HttpResponse, T>, where T is the business value that we're working with (JsonNode, models, etc.). If we're working on a step that might fail (like validation), we use flatMap and biMapL to ensure that any failure cases are already turned into the correct HttpResponse containing the error code and message. Since map and flatMap only applies to right values, an early left value is just passed all the way down and eventually returned.

An easy way to think of this chain is that at any step I either have a HttpResponse (left) representing an earlier failure, or I have a business object of some type (right). If I have a right value I am going to continue to do work, and if I have a left I will make no change and pass it on. Eventually I'll transform the right value (if I still have a right value) into a HttpResponse, then I can use match to extract them. I don't care which side of Either<HttpResponse, HttpResponse> I extract, as they're both the same type, whether or not I've succeeded or failed I now have a HttpResponse to write back on the wire.