Search code examples
scalauuidscala-catscirce

Scala, cats - convert FUUID with Circe


I use this library https://christopherdavenport.github.io/fuuid/ for creating ID of custom object and persist them into databse. I have a simple case class which is my model:

import io.chrisdavenport.fuuid.FUUID

case class Bet(
  betId: Option[FUUID],
  home: String,
  away: String,
  stake: BigDecimal,
  betType: String)

I used FUUID here as an Option parameter. I have also a routes created with Http4s which should take json from input and map it into model:

class BettingRoutes[F[_] : Async](service: BettingService[F]) extends Http4sDsl[F] {

  def routes: HttpRoutes[F] = HttpRoutes.of[F] {
    case req@PUT -> Root / "bets" =>
      for {
        bet <- req.as[Bet]
        created <- service.put(bet)
        response <- Created(created)
      } yield response
   }
}

I also added some implicits to encode and decode from Circe:

object jsons {
  implicit def circeDecoder[A[_] : Sync, B: Decoder]: EntityDecoder[A, B] = jsonOf[A, B]
  implicit def circeEncoder[A[_] : Sync, B: Encoder]: EntityEncoder[A, B] = jsonEncoderOf[A, B]
}

The problem is - when I want to compile project, I got an errors like this in route class:

Error:(23, 22) Cannot decode into a value of type model.Bet, because no EntityDecoder[F, model.Bet] instance could be found.
        bet <- req.as[Bet]

Error:(23, 22) not enough arguments for method as: (implicit F: cats.Functor[F], implicit decoder: org.http4s.EntityDecoder[F,model.Bet])F[model.Bet].
Unspecified value parameter decoder.
        bet <- req.as[Bet]

Error:(25, 28) Cannot convert from model.Bet to an Entity, because no EntityEncoder[F, model.Bet] instance could be found.
        response <- Created(created)

etc. I investigated it and it appears because of using FUUID. I changed all FUUID classes to Long and after this just to java's UUID and then everything compile correctly without errors. The problem is only with FUUID and probably with conversion of it. I tried to use Circe Integration as It was shown in FUUID link above, but it did not help. Do you know how to fix this code to compile everything with fuuid and circe? I am new to cats and connected libs, so maybe it is a simple mistake, but it is not trivial for me now.


Solution

  • In order to have EntityDecoder[F, Bet] via jsons.circeDecoder we firstly need Decoder[Bet]. It can be auto-generated by Circe if we have decoders for all fields. The thing is there is Decoder[UUID] but no Decoder[FUUID].

    So just define necessary implicit

    implicit val fuuidDecoder: Decoder[FUUID] = Decoder[UUID].map(FUUID.fromUUID)
    

    Similarly for encoders

    implicit val fuuidEncoder: Encoder[FUUID] = Encoder[UUID].contramap(FUUID.Unsafe.toUUID)