I am curious about what's the approach you'd follow to allow run-time input/state change the way circe Encoders
and Decoders
serialize and de-serialize a type.
For example, imagine you want to redact values depending on certain run-time value:
implicit def sensitiveEncoder[T, RedactedT](
implicit redactedEncoderEvidence: Encoder[RedactedT],
encoderEvidence: Encoder[T],
context: SerdesContext
): Encoder[Sensitive[T, RedactedT]] =
if (context.redactSecrets) {
redactedEncoderEvidence.contramap[Sensitive[T, RedactedT]] {
_.redacted
}
} else {
encoderEvidence.contramap[Sensitive[T, RedactedT]] {
_.value
}
}
I was able to do that with Spray Json and Circe (semi automatic derivation) using the same idea: Provide the encoders as functions from the type I want to depend on to Encoder[T]
. e.g:
implicit val barEncoder: SerdesContext => Encoder[Bar] = {
implicit serdesContext => deriveEncoder[Bar]
}
And allow seamless derivation with:
implicit def applyContextParam[T, F[_]](
implicit f: SerdesContext => F[T],
serdesContext: SerdesContext
): F[T] = f(serdesContext)
( https://github.com/pfcoperez/trycirce/blob/master/src/main/scala/org/pfcoperez/Models.scala )
Note that ^ is just a "demo". The idea here is to allow seamless composition with encoders from different sources.
With this, it is possible to generate the instance of the encoder from the run-time state.
Is this something you've ever tried to do? If so, did you follow a radically different approach?