Skip to content

[BUG/Question]: Could not find implicit value for evidence parameter of type upickle.default.ReadWriter[T] #1939

@cbcoutinho

Description

@cbcoutinho

Tapir: 1.0.0-M1
uPickle: 1.5.0
sttp: 3.5.1

Scala version: 2.12.13

Describe the bug

I am working with a JSON document that omits optional values, yet I can't figure out how to use optional fields with tapir and uPickle.

I would like to generate a client that can accept all to accept all three example responses for Message. Currently the commented baseEndpoint does not compile because Tapir cannot find an implicit value. Otherwise the tests below pass w.r.t uPickle

I'm sure this is an easy question but it's not clear from the example (TapirJsonuPickleTests.scala) how to use a custom encoder/decoder with jsonBody.

How to reproduce?

package com.example

import org.scalatest.flatspec.AnyFlatSpec
import sttp.tapir._
import sttp.tapir.generic.auto._
import sttp.tapir.json.upickle._

object TapirJsonuPickleCodec extends TapirJsonuPickle

object OptionPickler extends upickle.AttributeTagged {
  override implicit def OptionWriter[T: Writer]: Writer[Option[T]] =
    implicitly[Writer[T]].comap[Option[T]] {
      case Some(x) => x
      case None    => null.asInstanceOf[T]
    }

  override implicit def OptionReader[T: Reader]: Reader[Option[T]] =
    new Reader.Delegate[Any, Option[T]](implicitly[Reader[T]].map(Some(_))) {
      override def visitNull(i: Int) = None
    }
}

class TapirJsonSpec extends AnyFlatSpec {

  import OptionPickler.{ ReadWriter, macroRW, read }

  case class Message(a: String, b: Option[String] = None)
  object Message {
    implicit val rw: ReadWriter[Message] = macroRW
  }

  // What does a messageDecoder have to do with `jsonBody`?
  // val messageDecoder: JsonCodec[Message] = TapirJsonuPickleCodec.readWriterCodec[Message]

  // val baseEndpoint: PublicEndpoint[String, String, Message, Any] = endpoint
  // .in(path[String]("id"))
  // .errorOut(stringBody)
  // .out(jsonBody[Message])

  it should "parse json" in {
    val str = """{"a": "1", "b": "2"}"""
    read[Message](str)
  }

  it should "handle nulls" in {
    val str = """{"a": "1", "b": null}"""
    read[Message](str)
  }

  it should "handle missing values" in {
    val str = """{"a": "1"}"""
    read[Message](str)
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions