Skip to content

Commit

Permalink
Release 1.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
adamw committed Sep 30, 2022
1 parent 34fbda2 commit 179744c
Show file tree
Hide file tree
Showing 25 changed files with 173 additions and 71 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ tapir documentation is available at [tapir.softwaremill.com](http://tapir.softwa
Add the following dependency:

```sbt
"com.softwaremill.sttp.tapir" %% "tapir-core" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-core" % "1.1.2"
```

Then, import:
Expand Down
4 changes: 2 additions & 2 deletions doc/docs/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ these steps can be done separately, giving you complete control over the process
To generate OpenAPI documentation and expose it using the Swagger UI in a single step, first add the dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "1.1.2"
```

Then, you can interpret a list of endpoints using `SwaggerInterpreter`. The result will be a list of file-serving
Expand Down Expand Up @@ -55,7 +55,7 @@ for details.
Similarly as above, you'll need the following dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "1.1.2"
```

And the server endpoints can be generated using the `sttp.tapir.redoc.bundle.RedocInterpreter` class.
Expand Down
2 changes: 1 addition & 1 deletion generated-doc/out/client/http4s.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Add the dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-http4s-client" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-http4s-client" % "1.1.2"
```

To interpret an endpoint definition as an `org.http4s.Request[F]`, import:
Expand Down
2 changes: 1 addition & 1 deletion generated-doc/out/client/play.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Add the dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-play-client" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-play-client" % "1.1.2"
```

To make requests using an endpoint definition using the [play client](https://github.com/playframework/play-ws), import:
Expand Down
4 changes: 2 additions & 2 deletions generated-doc/out/client/sttp.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Add the dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "1.1.2"
```

To make requests using an endpoint definition using the [sttp client](https://github.com/softwaremill/sttp), import:
Expand Down Expand Up @@ -102,7 +102,7 @@ In this case add the following dependencies (note the [`%%%`](https://www.scala-
instead of the usual `%%`):

```scala
"com.softwaremill.sttp.tapir" %%% "tapir-sttp-client" % "1.1.1"
"com.softwaremill.sttp.tapir" %%% "tapir-sttp-client" % "1.1.2"
"io.github.cquiroz" %%% "scala-java-time" % "2.2.0" // implementations of java.time classes for Scala.JS
```

Expand Down
2 changes: 1 addition & 1 deletion generated-doc/out/docs/asyncapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
To use, add the following dependencies:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-docs" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-docs" % "1.1.2"
"com.softwaremill.sttp.apispec" %% "asyncapi-circe-yaml" % "..." // see https://github.com/softwaremill/sttp-apispec
```

Expand Down
14 changes: 9 additions & 5 deletions generated-doc/out/docs/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ these steps can be done separately, giving you complete control over the process
To generate OpenAPI documentation and expose it using the Swagger UI in a single step, first add the dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "1.1.2"
```

Then, you can interpret a list of endpoints using `SwaggerInterpreter`. The result will be a list of file-serving
Expand Down Expand Up @@ -55,7 +55,7 @@ for details.
Similarly as above, you'll need the following dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "1.1.2"
```

And the server endpoints can be generated using the `sttp.tapir.redoc.bundle.RedocInterpreter` class.
Expand All @@ -65,7 +65,7 @@ And the server endpoints can be generated using the `sttp.tapir.redoc.bundle.Red
To generate the docs in the OpenAPI yaml format, add the following dependencies:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-openapi-docs" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-openapi-docs" % "1.1.2"
"com.softwaremill.sttp.apispec" %% "openapi-circe-yaml" % "..." // see https://github.com/softwaremill/sttp-apispec
```

Expand Down Expand Up @@ -136,12 +136,12 @@ The modules `tapir-swagger-ui` and `tapir-redoc` contain server endpoint definit
yaml format, will expose it using the given context path. To use, add as a dependency either
`tapir-swagger-ui`:
```scala
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui" % "1.1.2"
```

or `tapir-redoc`:
```scala
"com.softwaremill.sttp.tapir" %% "tapir-redoc" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-redoc" % "1.1.2"
```

Then, you'll need to pass the server endpoints to your server interpreter. For example, using akka-http:
Expand Down Expand Up @@ -261,11 +261,15 @@ import io.circe.generic.auto._

import sttp.tapir.docs.apispec.DocsExtension
import sttp.tapir.docs.apispec.DocsExtensionAttribute._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter

case class FruitAmount(fruit: String, amount: Int)

case class MyExtension(string: String, int: Int)

implicit val fruitAmountSchemaWithMyExtension: Schema[FruitAmount] =
Schema.derived[FruitAmount].docsExtension("hello", MyExtension("world", 42))

val sampleEndpoint =
endpoint.post
.in("path-hello" / path[String]("world").docsExtension("x-path", 22))
Expand Down
12 changes: 6 additions & 6 deletions generated-doc/out/endpoint/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The `tapir-cats` module contains additional instances for some [cats](https://ty
datatypes as well as additional syntax:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-cats" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-cats" % "1.1.2"
```

- `import sttp.tapir.integ.cats.codec._` - brings schema, validator and codec instances
Expand All @@ -26,7 +26,7 @@ If you use [refined](https://github.com/fthomas/refined), the `tapir-refined` mo
validators for `T Refined P` as long as a codec for `T` already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-refined" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-refined" % "1.1.2"
```

You'll need to extend the `sttp.tapir.codec.refined.TapirCodecRefined`
Expand All @@ -47,7 +47,7 @@ The `tapir-enumeratum` module provides schemas, validators and codecs for [Enume
enumerations. To use, add the following dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-enumeratum" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-enumeratum" % "1.1.2"
```

Then, `import sttp.tapir.codec.enumeratum._`, or extends the `sttp.tapir.codec.enumeratum.TapirCodecEnumeratum` trait.
Expand Down Expand Up @@ -87,7 +87,7 @@ If you use [scala-newtype](https://github.com/estatico/scala-newtype), the `tapi
schemas for types with a `@newtype` and `@newsubtype` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-newtype" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-newtype" % "1.1.2"
```

Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.newtype.TapirCodecNewType` trait to bring the implicit values into scope.
Expand All @@ -98,7 +98,7 @@ If you use [monix newtypes](https://github.com/monix/newtypes), the `tapir-monix
schemas for types which extend `NewtypeWrapped` and `NewsubtypeWrapped` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-monix-newtype" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-monix-newtype" % "1.1.2"
```

Then, `import sttp.tapir.codec.monix.newtype._`, or extend the `sttp.tapir.codec.monix.newtype.TapirCodecMonixNewType` trait to bring the implicit values into scope.
Expand All @@ -110,7 +110,7 @@ For details refer to [derevo documentation](https://github.com/tofu-tf/derevo#in
To use, add the following dependency:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-derevo" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-derevo" % "1.1.2"
```

Then you can derive schema for your ADT along with other typeclasses besides ADT declaration itself:
Expand Down
32 changes: 14 additions & 18 deletions generated-doc/out/endpoint/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,24 @@ the json codec that is in scope.
## JSON as string

If you'd like to work with JSON bodies in a serialised `String` form, instead of integrating on a higher level using
one of the libraries mentioned below, this is also possible. Note that in this case, the serialising/deserialising
of the body must be part of the [server logic](../server/logic.md).
one of the libraries mentioned below, you should use the `stringJsonBody` input/output. Note that in this case, the
serialising/deserialising of the body must be part of the [server logic](../server/logic.md).

The `stringBody` body input/output will work, however by default it uses the `text/plain` content type. This can be
customised, by creating a string-based body with the correct codec format (which is a tapir wrapper for media types):
A schema can be provided in this case as well:

```scala
import sttp.tapir._
stringBodyUtf8AnyFormat(Codec.string.format(CodecFormat.Json()))

// or, providing a schema:
import sttp.tapir.generic.auto._
case class MyBody(field: Int)
stringBodyUtf8AnyFormat(Codec.id(CodecFormat.Json(), implicitly[Schema[MyBody]].as[String]))
stringJsonBody.schema(implicitly[Schema[MyBody]].as[String])
```

## Circe

To use [Circe](https://github.com/circe/circe), add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonCirce` trait, see [MyTapir](../mytapir.md)):
Expand Down Expand Up @@ -122,7 +118,7 @@ Now the above JSON object will render as
To use [µPickle](http://www.lihaoyi.com/upickle/) add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-upickle" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-upickle" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonuPickle` trait, see [MyTapir](../mytapir.md) and add `TapirJsonuPickle` not `TapirCirceJson`):
Expand Down Expand Up @@ -157,7 +153,7 @@ For more examples, including making a custom encoder/decoder, see [TapirJsonuPic
To use [Play JSON](https://github.com/playframework/play-json) add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-play" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-play" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonPlay` trait, see [MyTapir](../mytapir.md) and add `TapirJsonPlay` not `TapirCirceJson`):
Expand All @@ -173,7 +169,7 @@ Play JSON requires `Reads` and `Writes` implicit values in scope for each type y
To use [Spray JSON](https://github.com/spray/spray-json) add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-spray" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-spray" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonSpray` trait, see [MyTapir](../mytapir.md) and add `TapirJsonSpray` not `TapirCirceJson`):
Expand All @@ -189,7 +185,7 @@ Spray JSON requires a `JsonFormat` implicit value in scope for each type you wan
To use [Tethys JSON](https://github.com/tethys-json/tethys) add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-tethys" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-tethys" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonTethys` trait, see [MyTapir](../mytapir.md) and add `TapirJsonTethys` not `TapirCirceJson`):
Expand All @@ -205,7 +201,7 @@ Tethys JSON requires `JsonReader` and `JsonWriter` implicit values in scope for
To use [Jsoniter-scala](https://github.com/plokhotnyuk/jsoniter-scala) add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-jsoniter-scala" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-jsoniter-scala" % "1.1.2"
```

Next, import the package (or extend the `TapirJsonJsoniter` trait, see [MyTapir](../mytapir.md) and add `TapirJsonJsoniter` not `TapirCirceJson`):
Expand All @@ -221,15 +217,15 @@ Jsoniter Scala requires `JsonValueCodec` implicit value in scope for each type y
To use [json4s](https://github.com/json4s/json4s) add the following dependencies to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-json4s" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-json4s" % "1.1.2"
```

And one of the implementations:

```scala
"org.json4s" %% "json4s-native" % "4.0.5"
"org.json4s" %% "json4s-native" % "4.0.6"
// Or
"org.json4s" %% "json4s-jackson" % "4.0.5"
"org.json4s" %% "json4s-jackson" % "4.0.6"
```

Next, import the package (or extend the `TapirJson4s` trait, see [MyTapir](../mytapir.md) and add `TapirJson4s` instead of `TapirCirceJson`):
Expand All @@ -252,7 +248,7 @@ implicit val formats: Formats = org.json4s.jackson.Serialization.formats(NoTypeH
To use [zio-json](https://github.com/zio/zio-json), add the following dependency to your project:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-json-zio" % "1.1.1"
"com.softwaremill.sttp.tapir" %% "tapir-json-zio" % "1.1.2"
```
Next, import the package (or extend the `TapirJsonZio` trait, see [MyTapir](../mytapir.md) and add `TapirJsonZio` instead of `TapirCirceJson`):

Expand Down
101 changes: 101 additions & 0 deletions generated-doc/out/endpoint/xml.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Working with XML

Enabling support for XML is a matter of implementing proper [`XmlCodec[T]`](codecs.md) and providing it in scope.
This enables encoding objects to XML strings, and decoding XML strings to objects.
Implementation is fairly easy, and for now, one guide on how to integrate with scalaxb is provided.

```eval_rst
.. note::
Note, that implementing `XmlCodec[T]` would require deriving not only XML library encoders/decoders,
but also tapir related `Schema[T]`. These are completely separate - any customization e.g. for field
naming or inheritance strategies must be done separately for both derivations.
For more details see sections on [schema derivation](schemas.md) and on supporting [custom types](customtypes.md) in general.
```

## Scalaxb

If you possess the XML Schema definition file (`.xsd` file) consider using the scalaxb tool,
which generates needed models and serialization/deserialization logic.
To use the tool please follow the documentation on [setting up](https://scalaxb.org/setup) and
[running](https://scalaxb.org/running-scalaxb) scalaxb.

After code generation, create the `TapirXmlScalaxb` trait (or trait with another name of your choosing) and add the following code snippet:

```scala
import generated.`package`.defaultScope // import may differ depending on location of generated code
import scalaxb.XMLFormat // import may differ depending on location of generated code
import scalaxb.`package`.{fromXML, toXML} // import may differ depending on location of generated code
import sttp.tapir.Codec.XmlCodec
import sttp.tapir.DecodeResult.{Error, Value}
import sttp.tapir.{Codec, EndpointIO, Schema, stringBodyUtf8AnyFormat}

import scala.xml.{NodeSeq, XML}

trait TapirXmlScalaxb {
case class XmlElementLabel(label: String)

def xmlBody[T: XMLFormat: Schema](implicit l: XmlElementLabel): EndpointIO.Body[String, T] = stringBodyUtf8AnyFormat(scalaxbCodec[T])

implicit def scalaxbCodec[T: XMLFormat: Schema](implicit label: XmlElementLabel): XmlCodec[T] = {
Codec.xml((s: String) =>
try {
Value(fromXML[T](XML.loadString(s)))
} catch {
case e: Exception => Error(s, e)
}
)((t: T) => {
val nodeSeq: NodeSeq = toXML[T](obj = t, elementLabel = label.label, scope = defaultScope)
nodeSeq.toString()
})
}
}
```
This creates `XmlCodec[T]` that would encode / decode the types with `XMLFormat`, `Schema` and with `XmlElementLabel` provided in scope.
It also introduces `xmlBody` helper method, which allows you to easily express, that the declared endpoint consumes or returns XML.


Next to this trait, you might want to introduce `xml` package object to simplify imports.
```scala
package object xml extends TapirXmlScalaxb
```

From now on, XML serialization/deserialization would work for all classes generated from `.xsd` file as long as
`XMLFormat`, `Schema` and `XmlElementLabel` would be implicitly provided in the scope.
`XMLFormat` is scalaxb related, allowing for XML encoding / decoding.
[`Schema`](schemas.md) is tapir related, used primarily when generating documentation and validating incoming values.
And `XmlElementLabel` is required by scalaxb code when encoding to XML to give proper top node name.

Usage example:
```scala
import sttp.tapir.{PublicEndpoint, endpoint}
import cats.effect.IO
import generated.Outer // import may differ depending on location of generated code
import sttp.tapir.generic.auto._ // needed for Schema derivation
import sttp.tapir.server.ServerEndpoint

object Endpoints {
import xml._ // imports tapir related serialization / deserialization logic

implicit val label: XmlElementLabel = XmlElementLabel("outer") // `label` is needed by scalaxb code to properly encode the top node of the xml

val xmlEndpoint: PublicEndpoint[Outer, Unit, Outer, Any] = endpoint.post // `Outer` is a class generated by scalaxb based on .xsd file.
.in("xml")
.in(xmlBody[Outer])
.out(xmlBody[Outer])
}
```

If the generation of OpenAPI documentation is required, consider adding OpenAPI doc extension on schema providing XML
namespace as described in the "Prefixes and Namespaces" section at [OpenAPI documentation regarding handling XML](https://swagger.io/docs/specification/data-models/representing-xml/).
This would add `xmlns` property to example request/responses at swagger, which is required by scalaxb to properly deserialize XML.
For more information on adding OpenAPI doc extension in tapir refer to [documentation](../docs/openapi.md#openapi-specification-extensions).

Adding xml namespace doc extension to `Outer`'s `Schema` example:
```scala
case class XmlNamespace(namespace: String)
implicit val outerSchemaWithXmlNamespace: Schema[Outer] = implicitly[Derived[Schema[Outer]]].value
.docsExtension("xml", XmlNamespace("http://www.example.com/innerouter"))
```

Also, you might want to check the repository with [example project](https://github.com/softwaremill/tapir-scalaxb-example) showcasing integration with tapir and scalaxb.
Loading

0 comments on commit 179744c

Please sign in to comment.