Implicits guide for custom types¶
A could not find implicit value
error can be sometimes puzzling, so here’s a short summary of what kind of implicits
tapir uses for supporting custom types.
In general, when using a custom type in any context, an implicit Codec[T, _, _]
is required. Codecs for custom types
can be either derived automatically, or created basing on existing codecs.
Path, query parameters and headers¶
When using a custom type for a path parameter, query parameter or header value, you’ll need a codec with the
text/plain
media type. You can use an existing codec and map over it, to create a new one. For example:
case class MyId(...)
object MyId {
def parse(s: String): Try[String] = ...
}
def decode(s: String): DecodeResult[MyId] = MyId.parse(s) match {
case Success(v) => DecodeResult.Value(v)
case Failure(f) => DecodeResult.Error(s, f)
}
def encode(id: MyId): String = id.toString
implicit val myIdCodec: Codec[MyId, TextPlain, _] = Codec.stringPlainCodecUtf8
.mapDecode(decode)(encode)
Text and binary bodies¶
The approach for text and binary bodies is the same as for queries/paths/headers. To support a custom types, you’ll
need to map over an existing codec, for example Codec.byteArrayCodec
or Codec.stringPlainCodecUtf8
, and assign]
the result to an implicit value.
JSON bodies¶
When working with json bodies, the custom types can be much more complex than when mapping a query or path parameter.
Using the circe integration, a Codec[T, Json, _]
, where T
is a case class
, can be automatically derived given the
following implicit values:
io.circe.Encoder[T]
io.circe.Decoder[T]
tapir.SchemaFor[T]
The circe encoders/decoders have to be provided using one of the methods supported by Circe, e.g. by importing
import io.circe.generic.auto._
.
The SchemaFor[T]
can be auto-generated using Magnolia, or provided by hand. See json for more details.
In the future, it would be ideal if encoders/decoders could be derived automatically from the schema. For now however, the schema and the json encoders have to be provided separately.
Form bodies¶
When mapping either url-encoded or multipart form bodies, for each field, a plain codec has to be available
in the implicit scope. That is, a value of type Codec[R, TextPlain, _]
, for each R
which is a field of the case
class to which the data is being mapped.