`oneOfVariant` and Scala 3 `enum`

Hello again! :wave:

I’m using zio-json and tapir, and trying to use .errorOut(oneOf[QueryValidationError](oneOfVariant[SyntaxError](...), ...)).

I have this code:

  enum QueryValidationError(val message: String) {
    case InvalidRequestError(msg: String) extends QueryValidationError(msg)
    case SyntaxError(msg: String)         extends QueryValidationError(msg)
    case CompilationError(msg: String)    extends QueryValidationError(msg)
  }

  object QueryValidationError {
    given JsonCodec[QueryValidationError] = DeriveJsonCodec.gen
  }

and the my code on the tapir side doesn’t compile because there are no given instances for the members of the enum. I’m not sure if this is a tapir thing or zio-json thing, and would really like to know how to do this :slight_smile:

Thank you very much! :heart:

Hello, Ben!

In case of enums you need json codecs for each variant. Here’s a mini example of a working endpoint (based on the Adopt Tapir template):

  enum QueryValidationError(val message: String) {
    case InvalidRequestError(msg: String) extends QueryValidationError(msg)
    case SyntaxError(msg: String) extends QueryValidationError(msg)
    case CompilationError(msg: String) extends QueryValidationError(msg)
  }

  object QueryValidationError {
    given validationError: zio.json.JsonCodec[SyntaxError] = DeriveJsonCodec.gen[SyntaxError]
    given compilationError: zio.json.JsonCodec[CompilationError] = DeriveJsonCodec.gen[CompilationError]
    given invalidRequestError: zio.json.JsonCodec[InvalidRequestError] = DeriveJsonCodec.gen[InvalidRequestError]
  }

  import QueryValidationError._

  val booksListing: PublicEndpoint[Unit, QueryValidationError, List[Book], Any] = endpoint.get
    .in("books" / "list" / "all")
    .out(jsonBody[List[Book]])
    .errorOut(
      oneOf(
        oneOfVariant(statusCode(StatusCode.BadRequest).and(jsonBody[SyntaxError])),
        oneOfVariant(
          statusCode(StatusCode.Unauthorized).and(jsonBody[InvalidRequestError])
        ),
        oneOfDefaultVariant(statusCode(StatusCode.InternalServerError).and(jsonBody[CompilationError]))
      )
    )
  val booksListingServerEndpoint: ZServerEndpoint[Any, Any] = booksListing.serverLogic(_ => ZIO.succeed(Left(SyntaxError("oh no!"))))
1 Like

Thank you so much! :star_struck: