I have error model like:
sealed trait HttpError {
val msg: String
val cause: String
}
final case class HttpDecodingError(cause: String) extends HttpError {
override val msg: String = "Decoding error"
}
final case class HttpInternalServerError(msg: String, cause: String) extends HttpError
case object HttpUnauthorizedError extends HttpError {
override val msg: String = "Invalid credentials"
override val cause: String = ""
}
final case class HttpBadRequestError(msg: String, cause: String) extends HttpError
in my route I generate http error type based on this model ie:
.foldM(
{
case error: HttpDecodingError => BadRequest(error.asInstanceOf[HttpError])
case error: HttpInternalServerError => InternalServerError(error.asInstanceOf[HttpError])
case HttpUnauthorizedError => Unauthorized(withChallenge("Invalid credentials"))
case error: HttpBadRequestError => BadRequest(error.asInstanceOf[HttpError])
},
Ok(_)
)
but problem is that I need to add this asInstanceOf, otherwise circe does not see encoder. My encoder looks like:
implicit val encodeHttpError: Encoder[HttpError] = (error: HttpError) =>
Json.obj(("msg", Json.fromString(error.msg)), ("cause", Json.fromString(error.cause)))
is there a way to avoid doing asInstanceOf there?
You can't use encoder for
HttpError
for it's subclasses, becauseEncoder
is invariant (it would work if it would be covariant).One solution you could use is to define encoder using parametrized
def
instead ofval
:This way you'd have instance of encoder for all subtypes of
HttpError
as well as forHttpError
.