Skip to content

Instantly share code, notes, and snippets.

@BenFradet
Last active April 10, 2020 20:45
Show Gist options
  • Save BenFradet/bab012d44fe72b8bd6be73133c098863 to your computer and use it in GitHub Desktop.
Save BenFradet/bab012d44fe72b8bd6be73133c098863 to your computer and use it in GitHub Desktop.
Chaining decoders
import cats.effect.{IO, Sync}
import fs2.Stream
import io.circe.{Decoder, Encoder, Json}
import io.circe.generic.semiauto._
import io.circe.syntax._
import org.http4s.{EntityDecoder, EntityEncoder, Response, Status}
import org.http4s.circe._
sealed trait A
final case class B(error: String) extends A
final case class C(message: String) extends A
implicit val bd: Decoder[B] = deriveDecoder[B]
implicit val be: Encoder[B] = deriveEncoder[B]
implicit val cd: Decoder[C] = deriveDecoder[C]
implicit val ce: Encoder[C] = deriveEncoder[C]
def decoder[F[_]: Sync]: EntityDecoder[F, A] =
jsonOf[F, B].widen.orElse(jsonOf[F, C].widen)
def createBody[F[_]](js: Json): Stream[F, Byte] =
implicitly[EntityEncoder[F, Json]].toEntity(js).body
val response1 = Response[IO](status = Status(200), body = createBody(B("error").asJson))
println(response1.attemptAs[A](decoder).value.unsafeRunSync())
// Left(org.http4s.InvalidMessageBodyFailure: Invalid message body: Could not decode JSON: {
// "error" : "error"
//})
val response2 = Response[IO](status = Status(200), body = createBody(C("msg").asJson))
println(response2.attemptAs[A](decoder).value.unsafeRunSync())
// Right(C(msg))
@dcsobral
Copy link

Ouch!

@dcsobral
Copy link

Are you sure this isn't an issue with Circe?

@BenFradet
Copy link
Author

Afaict no, because the solution was to rely on circe decoders directly: https://github.com/47degrees/github4s/pull/440/files#diff-b93ab619ec70a2dfcfee92460b1d5ac0R164-R167

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment