Fetch is built using Cats' Free monad construction and thus works out of the box with
cats syntax. Using Cats' syntax, we can make fetch declarations more concise, without
the need to use the combinators in the Fetch
companion object.
Fetch provides its own instance of Applicative[Fetch]
. Whenever we use applicative
operations on more than one Fetch
, we know that the fetches are independent meaning
we can perform optimizations such as batching and concurrent requests.
If we were to use the default Applicative[Fetch]
operations, which are implemented in terms of flatMap
,
we wouldn't have information about the independency of multiple fetches.
The |@|
operator (cartesian builder) allows us to combine multiple independent fetches, even when they
are from different types, and apply a pure function to their results. We can use it
as a more powerful alternative to the product
method or Fetch#join
:
Notice how the queries to posts are batched.
import cats.syntax.cartesian._
val fetchThree: Fetch[(Post, User, Post)] = (getPost(1) |@| getUser(2) |@| getPost(2)).tupled
fetchThree.runA[Id]
// res: (Post(1,2,An article),User(2,@two),Post(2,3,Another article))
More interestingly, we can use it to apply a pure function to the results of various fetches.
val fetchFriends: Fetch[String] = (getUser(1) |@| getUser(2)).map((one, other) =>
s"${one.username} is friends with ${other.username}")
fetchFriends.runA[Id] shouldBe res0
The above example is equivalent to the following using the Fetch#join
method:
val fetchLoves: Fetch[String] = Fetch
.join(getUser(1), getUser(2))
.map({
case (one, other) =>
s"${one.username} loves ${other.username}"
})
fetchLoves.runA[Id] shouldBe res0