Ilja Tollu (9) [Avatar] Offline
#1
Hello, colleagues!
The following use case is typical for REST service, I believe.
Consider a POST-controller: it parses JSON data into some Entity (case class) andThen persists it into repository.
It returns `Created` response on success, otherwise it can be `Bad request` (parsing failed) or `Internal Server Error` (db operation failed).
So, we design EntityService like this:
    // Source can be PlayFramework's JsValue 
    trait EntityService[Source] {
        def parse(src: Source): \/[Errors, Entity]
        def persist(entity: Entity, repo: Repo): EitherT[Future, Errors, Entity]
    }


How should I modify this code to make it compose? ParsingService needs nor Repo, neither Future (it is non-blocking). Persisting needs both. Does this mean that should wrap parsing result into Future or EitherT or Kleisli?

In more complex use cases we may have a need to compose further i.e. use Kleisli composition when it comes to futures and eithers. But I tried to keep it simple.

Thank you!
Debasish Ghosh (116) [Avatar] Offline
#2
Composing effectful operations can be of many types. If you want failfast composition, then you need to go for monadic ones. You can have each of your functions return the monad of your choice, e.g. Error \/ Entity. Then you can use for-comprehensions to compose them. If you want to have fail slow composition, you can choose the applicative model. In Scalaz, Validation is one such abstraction which lets you compose multiple operations with error accumulation. I discuss both of these models in the book.

If you are using more than 1 monad, e.g. you mentioned about EitherT, then monad transformers is the way to go.

Let me know if you need more specific help on this. The book actually has quite a few examples of composing domain services using repositories.

Thanks.