Circe provides compile-time derived codecs for en/decode json into case classes. A simple example looks like this:
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
case class User(id: Long, name: String)
val user = User(1, "John Doe")
// {"id":1,"name":"John Doe"}
val json = user.asJson.noSpaces
// Right(User(1L, "John Doe"))
val res: Either[Error, User] = decode[User](json)