Json values are supported through codecs which encode/decode values to json strings. However, third-party libraries are needed for actual json parsing/printing. Currently, Circe, µPickle and Play JSON are supported.
To use Circe add the following dependency to your project:
"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.12.9"
Next, import the package (or extend the TapirJsonCirce
trait, see MyTapir):
import sttp.tapir.json.circe._
This will allow automatically deriving Codec
s which, given an in-scope circe Encoder
/Decoder
and a Schema
,
will create a codec using the json media type. Circe includes a couple of approaches to generating encoders/decoders
(manual, semi-auto and auto), so you may choose whatever suits you.
Note that when using Circe's auto derivation, any encoders/decoders for custom types must be in scope as well.
For example, to automatically generate a JSON codec for a case class:
import sttp.tapir._
import sttp.tapir.json.circe._
import io.circe.generic.auto._
case class Book(author: String, title: String, year: Int)
val bookInput: EndpointIO[Book] = jsonBody[Book]
Circe lets you select an instance of io.circe.Printer
to configure the way JSON objects are rendered. By default
Tapir uses Printer.nospaces
, which would render:
Json.obj(
"key1" -> Json.fromString("present"),
"key2" -> Json.Null
)
as
{"key1":"present","key2":null}
Suppose we would instead want to omit null
-values from the object and pretty-print it. You can configure this by
overriding the jsonPrinter
in tapir.circe.json.TapirJsonCirce
:
object MyTapirJsonCirce extends TapirJsonCirce {
override def jsonPrinter: Printer = Printer.spaces2.copy(dropNullValues = true)
}
import MyTapirJsonCirce._
Now the above JSON object will render as
{"key1":"present"}
To use µPickle add the following dependency to your project:
"com.softwaremill.sttp.tapir" %% "tapir-json-upickle" % "0.12.9"
Next, import the package (or extend the TapirJsonuPickle
trait, see MyTapir and add TapirJsonuPickle
not TapirCirceJson
):
import sttp.tapir.json.upickle._
µPickle requires a ReadWriter in scope for each type you want to serialize. In order to provide one use the macroRW
macro in the companion object as follows:
import sttp.tapir._
import upickle.default._
import sttp.tapir.json.upickle._
case class Book(author: String, title: String, year: Int)
object Book {
implicit val rw: ReadWriter[Book] = macroRW
}
val bookInput: EndpointIO[Book] = jsonBody[Book]
Like Circe, µPickle allows you to control the rendered json output. Please see the Custom Configuration of the manual for details.
For more examples, including making a custom encoder/decoder, see TapirJsonuPickleTests.scala
To use Play JSON add the following dependency to your project:
"com.softwaremill.sttp.tapir" %% "tapir-json-play" % "0.12.9"
Next, import the package (or extend the TapirJsonPlay
trait, see MyTapir and add TapirJsonPlay
not TapirCirceJson
):
import sttp.tapir.json.play._
Play JSON requires Reads
and Writes
implicit values in scope for each type you want to serialize.
To use Spray JSON add the following dependency to your project:
"com.softwaremill.sttp.tapir" %% "tapir-json-spray" % "0.12.9"
Next, import the package (or extend the TapirJsonSpray
trait, see MyTapir and add TapirJsonSpray
not TapirCirceJson
):
import sttp.tapir.json.spray._
Spray JSON requires a JsonFormat
implicit value in scope for each type you want to serialize.
To add support for additional JSON libraries, see the sources for the Circe codec (which is just a couple of lines of code).
To derive json codecs automatically, not only implicits from the base library are needed (e.g. a circe
Encoder
/Decoder
), but also an implicit SchemaFor[T]
value, which provides a mapping between a type T
and its
schema. A schema-for value contains a single schema: Schema
field.
See custom types for details.
Read on about working with forms.