diff --git a/README.md b/README.md index a6a1257359..b3533a1c80 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ tapir documentation is available at [tapir.softwaremill.com](http://tapir.softwa Add the following dependency: ```sbt -"com.softwaremill.sttp.tapir" %% "tapir-core" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-core" % "0.20.0-M10" ``` Partial unification is now enabled by default from Scala 2.13. However, if you're using Scala 2.12 or older, then diff --git a/doc/docs/openapi.md b/doc/docs/openapi.md index a354308a3c..316c3800a0 100644 --- a/doc/docs/openapi.md +++ b/doc/docs/openapi.md @@ -7,7 +7,7 @@ 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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "0.20.0-M10" ``` Then, you can interpret a list of endpoints, as server endpoints exposing the Swagger UI, using `SwaggerInterpreter`. @@ -46,7 +46,7 @@ for details. Similarly as above, you'll need the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "0.20.0-M10" ``` And the server endpoints can be generated using the `sttp.tapir.redoc.bundle.RedocInterpreter` class. diff --git a/generated-doc/out/client/http4s.md b/generated-doc/out/client/http4s.md index 2ee986cc20..92c7bd8a27 100644 --- a/generated-doc/out/client/http4s.md +++ b/generated-doc/out/client/http4s.md @@ -3,7 +3,7 @@ Add the dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-http4s-client" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-http4s-client" % "0.20.0-M10" ``` To interpret an endpoint definition as an `org.http4s.Request[F]`, import: diff --git a/generated-doc/out/client/play.md b/generated-doc/out/client/play.md index 209c98b2b2..8266676e5e 100644 --- a/generated-doc/out/client/play.md +++ b/generated-doc/out/client/play.md @@ -3,7 +3,7 @@ Add the dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-play-client" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-play-client" % "0.20.0-M10" ``` To make requests using an endpoint definition using the [play client](https://github.com/playframework/play-ws), import: diff --git a/generated-doc/out/client/sttp.md b/generated-doc/out/client/sttp.md index 20a1a6e1aa..31081e4d5b 100644 --- a/generated-doc/out/client/sttp.md +++ b/generated-doc/out/client/sttp.md @@ -3,7 +3,7 @@ Add the dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "0.20.0-M10" ``` To make requests using an endpoint definition using the [sttp client](https://github.com/softwaremill/sttp), import: @@ -82,7 +82,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %%% "tapir-sttp-client" % "0.20.0-M10" "io.github.cquiroz" %%% "scala-java-time" % "2.2.0" // implementations of java.time classes for Scala.JS ``` diff --git a/generated-doc/out/docs/asyncapi.md b/generated-doc/out/docs/asyncapi.md index 43c7c77b3a..81d7d0a95f 100644 --- a/generated-doc/out/docs/asyncapi.md +++ b/generated-doc/out/docs/asyncapi.md @@ -3,8 +3,8 @@ To use, add the following dependencies: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-docs" % "0.20.0-M9" -"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-circe-yaml" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-docs" % "0.20.0-M10" +"com.softwaremill.sttp.tapir" %% "tapir-asyncapi-circe-yaml" % "0.20.0-M10" ``` Tapir contains a case class-based model of the asyncapi data structures in the `asyncapi/asyncapi-model` subproject (the diff --git a/generated-doc/out/docs/openapi.md b/generated-doc/out/docs/openapi.md index 73ee9f7e19..5cf871740e 100644 --- a/generated-doc/out/docs/openapi.md +++ b/generated-doc/out/docs/openapi.md @@ -7,7 +7,7 @@ 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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "0.20.0-M10" ``` Then, you can interpret a list of endpoints, as server endpoints exposing the Swagger UI, using `SwaggerInterpreter`. @@ -46,7 +46,7 @@ for details. Similarly as above, you'll need the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-redoc-bundle" % "0.20.0-M10" ``` And the server endpoints can be generated using the `sttp.tapir.redoc.bundle.RedocInterpreter` class. @@ -56,8 +56,8 @@ 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" % "0.20.0-M9" -"com.softwaremill.sttp.tapir" %% "tapir-openapi-circe-yaml" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-openapi-docs" % "0.20.0-M10" +"com.softwaremill.sttp.tapir" %% "tapir-openapi-circe-yaml" % "0.20.0-M10" ``` Tapir contains a case class-based model of the openapi data structures in the `openapi/openapi-model` subproject (the @@ -193,12 +193,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui" % "0.20.0-M10" ``` or `tapir-redoc`: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-redoc" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-redoc" % "0.20.0-M10" ``` Then, you'll need to pass the server endpoints to your server interpreter. For example, using akka-http: diff --git a/generated-doc/out/endpoint/customtypes.md b/generated-doc/out/endpoint/customtypes.md index 65c3e76ac8..cdaaabf477 100644 --- a/generated-doc/out/endpoint/customtypes.md +++ b/generated-doc/out/endpoint/customtypes.md @@ -80,6 +80,7 @@ In some cases, codecs can be automatically derived: * for supported [json](json.md) libraries * for urlencoded and multipart [forms](forms.md) +* for value classes (extending `AnyVal`) Automatic codec derivation usually requires other implicits, such as: diff --git a/generated-doc/out/endpoint/integrations.md b/generated-doc/out/endpoint/integrations.md index 870392b7d9..bbbdd4a907 100644 --- a/generated-doc/out/endpoint/integrations.md +++ b/generated-doc/out/endpoint/integrations.md @@ -6,7 +6,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-cats" % "0.20.0-M10" ``` - `import sttp.tapir.integ.cats.codec._` - brings schema, validator and codec instances @@ -18,7 +18,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-refined" % "0.20.0-M10" ``` You'll need to extend the `sttp.tapir.codec.refined.TapirCodecRefined` @@ -39,7 +39,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-enumeratum" % "0.20.0-M10" ``` Then, `import sttp.tapir.codec.enumeratum`, or extends the `sttp.tapir.codec.enumeratum.TapirCodecEnumeratum` trait. @@ -77,7 +77,7 @@ If you use [scala-newtype](https://github.com/estatico/scala-newtype), the `tapi schemas for a 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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-newtype" % "0.20.0-M10" ``` Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.enumeratum.TapirCodecNewType` trait to bring the implicit values into scope. @@ -89,7 +89,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-derevo" % "0.20.0-M10" ``` Then you can derive schema for your ADT along with other typeclasses besides ADT declaration itself: diff --git a/generated-doc/out/endpoint/json.md b/generated-doc/out/endpoint/json.md index f828900c0b..2744b42a67 100644 --- a/generated-doc/out/endpoint/json.md +++ b/generated-doc/out/endpoint/json.md @@ -17,7 +17,7 @@ the json codec that is in scope. To use Circe, add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonCirce` trait, see [MyTapir](../mytapir.md)): @@ -91,7 +91,7 @@ Now the above JSON object will render as To use µPickle add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-upickle" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-upickle" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonuPickle` trait, see [MyTapir](../mytapir.md) and add `TapirJsonuPickle` not `TapirCirceJson`): @@ -126,7 +126,7 @@ For more examples, including making a custom encoder/decoder, see [TapirJsonuPic To use Play JSON add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-play" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-play" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonPlay` trait, see [MyTapir](../mytapir.md) and add `TapirJsonPlay` not `TapirCirceJson`): @@ -142,7 +142,7 @@ Play JSON requires `Reads` and `Writes` implicit values in scope for each type y To use Spray JSON add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-spray" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-spray" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonSpray` trait, see [MyTapir](../mytapir.md) and add `TapirJsonSpray` not `TapirCirceJson`): @@ -158,7 +158,7 @@ Spray JSON requires a `JsonFormat` implicit value in scope for each type you wan To use Tethys JSON add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-tethys" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-tethys" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonTethys` trait, see [MyTapir](../mytapir.md) and add `TapirJsonTethys` not `TapirCirceJson`): @@ -174,7 +174,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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-jsoniter-scala" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonJsoniter` trait, see [MyTapir](../mytapir.md) and add `TapirJsonJsoniter` not `TapirCirceJson`): @@ -191,7 +191,7 @@ 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" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-json4s" % "0.20.0-M10" ``` And one of the implementations: @@ -222,7 +222,7 @@ implicit val formats: Formats = org.json4s.jackson.Serialization.formats(NoTypeH To use Zio JSON, add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-json-zio" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-json-zio" % "0.20.0-M10" ``` Next, import the package (or extend the `TapirJsonZio` trait, see [MyTapir](../mytapir.md) and add `TapirJsonZio` instead of `TapirCirceJson`): diff --git a/generated-doc/out/generator/sbt-openapi-codegen.md b/generated-doc/out/generator/sbt-openapi-codegen.md index 611fed0b4f..2625093d68 100644 --- a/generated-doc/out/generator/sbt-openapi-codegen.md +++ b/generated-doc/out/generator/sbt-openapi-codegen.md @@ -11,7 +11,7 @@ Add the sbt plugin to the `project/plugins.sbt`: ```scala -addSbtPlugin("com.softwaremill.sttp.tapir" % "sbt-openapi-codegen" % "0.20.0-M9") +addSbtPlugin("com.softwaremill.sttp.tapir" % "sbt-openapi-codegen" % "0.20.0-M10") ``` Enable the plugin for your project in the `build.sbt`: diff --git a/generated-doc/out/index.md b/generated-doc/out/index.md index 665ef8b2a9..7aac8d2a6d 100644 --- a/generated-doc/out/index.md +++ b/generated-doc/out/index.md @@ -11,6 +11,7 @@ input and output parameters. An endpoint specification can be interpreted as: * [Finatra](server/finatra.md) `http.Controller` * [Play](server/play.md) `Route` * [ZIO Http](server/ziohttp.md) `Http` + * [Armeria](server/armeria.md) `HttpServiceWithRoutes` * [aws](server/aws.md) through Lambda/SAM/Terraform * a client, which is a function from input parameters to output parameters. Currently supported: @@ -149,6 +150,7 @@ Development and maintenance of sttp tapir is sponsored by [SoftwareMill](https:/ server/play server/vertx server/ziohttp + server/armeria server/aws server/options server/interceptors diff --git a/generated-doc/out/quickstart.md b/generated-doc/out/quickstart.md index d464eb4dcb..2b42038b6c 100644 --- a/generated-doc/out/quickstart.md +++ b/generated-doc/out/quickstart.md @@ -3,7 +3,7 @@ To use tapir, add the following dependency to your project: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-core" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-core" % "0.20.0-M10" ``` This will import only the core classes needed to create endpoint descriptions. To generate a server or a client, you diff --git a/generated-doc/out/server/akkahttp.md b/generated-doc/out/server/akkahttp.md index 89ca42b5a0..a5039fc040 100644 --- a/generated-doc/out/server/akkahttp.md +++ b/generated-doc/out/server/akkahttp.md @@ -4,14 +4,14 @@ To expose an endpoint as an [akka-http](https://doc.akka.io/docs/akka-http/curre dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-akka-http-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-akka-http-server" % "0.20.0-M10" ``` This will transitively pull some Akka modules in version 2.6. If you want to force your own Akka version (for example 2.5), use sbt exclusion. Mind the Scala version in artifact name: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-akka-http-server" % "0.20.0-M9" exclude("com.typesafe.akka", "akka-stream_2.12") +"com.softwaremill.sttp.tapir" %% "tapir-akka-http-server" % "0.20.0-M10" exclude("com.typesafe.akka", "akka-stream_2.12") ``` Now import the object: diff --git a/generated-doc/out/server/armeria.md b/generated-doc/out/server/armeria.md new file mode 100644 index 0000000000..5b0fff0560 --- /dev/null +++ b/generated-doc/out/server/armeria.md @@ -0,0 +1,200 @@ +# Running as an Armeria server + +Endpoints can be mounted as `TapirService[S, F]` on top of [Armeria](https://armeria.dev)'s `HttpServiceWithRoutes`. + +Armeria interpreter can be used with different effect systems (cats-effect, ZIO) as well as Scala's standard `Future`. + +## Scala's standard `Future` + +Add the following dependency +```scala +"com.softwaremill.sttp.tapir" %% "tapir-armeria-server" % "0.20.0-M10" +``` + +and import the object: + +```scala +import sttp.tapir.server.armeria.ArmeriaFutureServerInterpreter +``` +to use this interpreter with `Future`. + +The `toService` method require a single, or a list of `ServerEndpoint`s, which can be created by adding +[server logic](logic.md) to an endpoint. + +```scala +import sttp.tapir._ +import sttp.tapir.server.armeria.ArmeriaFutureServerInterpreter +import scala.concurrent.Future +import com.linecorp.armeria.server.Server + +object Main { + // JVM entry point that starts the HTTP server + def main(args: Array[String]): Unit = { + val tapirEndpoint: PublicEndpoint[(String, Int), Unit, String, Any] = ??? // your definition here + def logic(s: String, i: Int): Future[Either[Unit, String]] = ??? // your logic here + val tapirService = ArmeriaFutureServerInterpreter().toService(tapirEndpoint.serverLogic((logic _).tupled)) + val server = Server + .builder() + .service(tapirService) // your endpoint is bound to the server + .build() + server.start().join() + } +} +``` + +This interpreter also supports streaming using Armeria Streams which is fully compatible with Reactive Streams: + +```scala +import sttp.capabilities.armeria.ArmeriaStreams +import sttp.tapir._ +import sttp.tapir.server.armeria.ArmeriaFutureServerInterpreter +import scala.concurrent.Future +import com.linecorp.armeria.common.HttpData +import com.linecorp.armeria.common.stream.StreamMessage +import org.reactivestreams.Publisher + +val streamingResponse: PublicEndpoint[Int, Unit, Publisher[HttpData], ArmeriaStreams] = + endpoint + .in("stream") + .in(query[Int]("key")) + .out(streamTextBody(ArmeriaStreams)(CodecFormat.TextPlain())) + +def streamLogic(foo: Int): Future[Publisher[HttpData]] = { + Future.successful(StreamMessage.of(HttpData.ofUtf8("hello"), HttpData.ofUtf8("world"))) +} + +val tapirService = ArmeriaFutureServerInterpreter().toService(streamingResponse.serverLogicSuccess(streamLogic)) +``` + +## Configuration + +Every endpoint can be configured by providing an instance of `ArmeriaFutureEndpointOptions`, see [server options](options.md) for details. +Note that Armeria automatically injects an `ExecutionContext` on top of Armeria's `EventLoop` to invoke the logic. + +## Cats Effect + +Add the following dependency +```scala +"com.softwaremill.sttp.tapir" %% "tapir-armeria-server-cats" % "0.20.0-M10" +``` +to use this interpreter with Cats Effect typeclasses. + +Then import the object: +```scala +import sttp.tapir.server.armeria.cats.ArmeriaCatsServerInterpreter +``` + +This object contains the `toService(e: ServerEndpoint[Fs2Streams[F], F])` method which returns a `TapirService[Fs2Streams[F], F]`. +An HTTP server can then be started as in the following example: + +```scala +import sttp.tapir._ +import sttp.tapir.server.armeria.cats.ArmeriaCatsServerInterpreter +import cats.effect._ +import cats.effect.std.Dispatcher +import com.linecorp.armeria.server.Server + +object Main extends IOApp { + override def run(args: List[String]): IO[ExitCode] = { + val tapirEndpoint: PublicEndpoint[String, Unit, String, Any] = ??? + def logic(req: String): IO[Either[Unit, String]] = ??? + + Dispatcher[IO] + .flatMap { dispatcher => + Resource + .make( + IO.async_[Server] { cb => + val tapirService = ArmeriaCatsServerInterpreter[IO](dispatcher).toService(tapirEndpoint.serverLogic(logic)) + + val server = Server + .builder() + .service(tapirService) + .build() + server.start().handle[Unit] { + case (_, null) => cb(Right(server)) + case (_, cause) => cb(Left(cause)) + } + } + )({ server => + IO.fromCompletableFuture(IO(server.closeAsync())).void + }) + } + .use(_ => IO.never) + } +} +``` + +This interpreter also supports streaming using FS2 streams: + +```scala +import sttp.capabilities.fs2.Fs2Streams +import sttp.tapir._ +import sttp.tapir.server.armeria.cats.ArmeriaCatsServerInterpreter +import cats.effect._ +import cats.effect.std.Dispatcher +import fs2._ + +val streamingResponse: Endpoint[Unit, Int, Unit, Stream[IO, Byte], Fs2Streams[IO]] = + endpoint + .in("stream") + .in(query[Int]("times")) + .out(streamTextBody(Fs2Streams[IO])(CodecFormat.TextPlain())) + +def streamLogic(times: Int): IO[Stream[IO, Byte]] = { + IO.pure(Stream.chunk(Chunk.array("Hello world!".getBytes)).repeatN(times)) +} + +def dispatcher: Dispatcher[IO] = ??? + +val tapirService = ArmeriaCatsServerInterpreter(dispatcher).toService(streamingResponse.serverLogicSuccess(streamLogic)) +``` + +## ZIO + +Add the following dependency + +```scala +"com.softwaremill.sttp.tapir" %% "tapir-armeria-server-zio" % "0.20.0-M10" +``` + +to use this interpreter with ZIO. + +Then import the object: +```scala +import sttp.tapir.server.armeria.zio.ArmeriaZioServerInterpreter +``` + +This object contains `toService(e: ServerEndpoint[ZioStreams, RIO[R, *]])` method which returns a `TapirService[ZioStreams, RIO[R, *]]`. +An HTTP server can then be started as in the following example: + +```scala +import sttp.tapir._ +import sttp.tapir.server.armeria.zio.ArmeriaZioServerInterpreter +import sttp.tapir.ztapir._ +import zio._ +import com.linecorp.armeria.server.Server + +object Main extends zio.App { + override def run(args: List[String]): URIO[ZEnv, ExitCode] = { + implicit val runtime = Runtime.default + + val tapirEndpoint: PublicEndpoint[String, Unit, String, Any] = ??? + def logic(key: String): UIO[String] = ??? + + ZManaged + .make(ZIO.fromCompletableFuture { + val tapirService = ArmeriaZioServerInterpreter().toService(tapirEndpoint.zServerLogic(logic)) + + val server = Server + .builder() + .service(tapirService) + .build() + server.start().thenApply[Server](_ => server) + }) { server => + ZIO.fromCompletableFuture(server.closeAsync()).orDie + }.useForever.as(ExitCode.success).orDie + } +} +``` + +This interpreter supports streaming using ZStreams. diff --git a/generated-doc/out/server/aws.md b/generated-doc/out/server/aws.md index cf250fe6ea..3ec4208383 100644 --- a/generated-doc/out/server/aws.md +++ b/generated-doc/out/server/aws.md @@ -13,7 +13,7 @@ To implement the Lambda function, a server interpreter is available, which takes Currently, only an interpreter integrating with cats-effect is available (`AwsCatsEffectServerInterpreter`). To use, add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-aws-lambda" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-aws-lambda" % "0.20.0-M10" ``` To configure API Gateway and the Lambda function, you can use: @@ -24,8 +24,8 @@ To configure API Gateway and the Lambda function, you can use: Add one of the following dependencies: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-aws-sam" % "0.20.0-M9" -"com.softwaremill.sttp.tapir" %% "tapir-aws-terraform" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-aws-sam" % "0.20.0-M10" +"com.softwaremill.sttp.tapir" %% "tapir-aws-terraform" % "0.20.0-M10" ``` ## Examples diff --git a/generated-doc/out/server/finatra.md b/generated-doc/out/server/finatra.md index 7b1de27af8..d8b1b072fa 100644 --- a/generated-doc/out/server/finatra.md +++ b/generated-doc/out/server/finatra.md @@ -4,7 +4,7 @@ To expose an endpoint as an [finatra](https://twitter.github.io/finatra/) server dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-finatra-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-finatra-server" % "0.20.0-M10" ``` and import the object: @@ -17,7 +17,7 @@ This interpreter supports the twitter `Future`. Or, if you would like to use cats-effect project, you can add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-finatra-server-cats" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-finatra-server-cats" % "0.20.0-M10" ``` and import the object: diff --git a/generated-doc/out/server/http4s.md b/generated-doc/out/server/http4s.md index eeed0336b9..d19a89371f 100644 --- a/generated-doc/out/server/http4s.md +++ b/generated-doc/out/server/http4s.md @@ -4,7 +4,7 @@ To expose an endpoint as an [http4s](https://http4s.org) server, first add the f dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-http4s-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-http4s-server" % "0.20.0-M10" ``` and import the object: diff --git a/generated-doc/out/server/logic.md b/generated-doc/out/server/logic.md index 625f4a8135..0d642b216c 100644 --- a/generated-doc/out/server/logic.md +++ b/generated-doc/out/server/logic.md @@ -109,6 +109,7 @@ There are also other variants of the methods that can be used to provide the ser * `serverLogicError(f: I => F[E])`: similarly for endpoints which always return an error * `serverLogicPure(f: I => Either[E, O])`: if the server logic function is pure, that is returns a strict value, not a description of side-effects +* `serverLogicOption(f: I => F[Option[O]])`: if the error type is a `Unit`, a `None` results is treated as an error Similar variants are available to provide the security logic. @@ -165,6 +166,18 @@ val secureHelloWorld1WithLogic: ServerEndpoint[Any, Future] = secureEndpoint.get } ``` +### Security logic with outputs + +When using `.serverSecurityLogic`, the result of the security function is treated as an input to the main server logic. +However, it might be desirable to provide some output as part of the security logic. This is possible using +`.serverSecurityLogicWithOutput` and its variants. + +The provided security function has to return a value for the output defined so far, and a value that will be provided +to the main server logic. The security output will contribute directly to the output of the whole endpoint, unless +an error response is returned. + +Additional outputs can be then added to the resulting partial endpoint. + ## Status codes By default, successful responses are returned with the `200 OK` status code, and errors with `400 Bad Request`. However, diff --git a/generated-doc/out/server/netty.md b/generated-doc/out/server/netty.md index fa4205e27d..04df99653a 100644 --- a/generated-doc/out/server/netty.md +++ b/generated-doc/out/server/netty.md @@ -5,7 +5,7 @@ To expose an endpoint using a [Netty](https://netty.io)-based server, first add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-netty-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-netty-server" % "0.20.0-M10" ``` Then, use: diff --git a/generated-doc/out/server/observability.md b/generated-doc/out/server/observability.md index 0398bc7126..77c6027eac 100644 --- a/generated-doc/out/server/observability.md +++ b/generated-doc/out/server/observability.md @@ -49,7 +49,7 @@ val labels = MetricLabels( Add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-prometheus-metrics" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-prometheus-metrics" % "0.20.0-M10" ``` `PrometheusMetrics` encapsulates `CollectorReqistry` and `Metric` instances. It provides several ready to use metrics as @@ -124,7 +124,7 @@ val prometheusMetrics = PrometheusMetrics[Future]("tapir", CollectorRegistry.def Add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-opentelemetry-metrics" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-opentelemetry-metrics" % "0.20.0-M10" ``` OpenTelemetry metrics are vendor-agnostic and can be exported using one diff --git a/generated-doc/out/server/play.md b/generated-doc/out/server/play.md index aa1984846f..8a9b2f0402 100644 --- a/generated-doc/out/server/play.md +++ b/generated-doc/out/server/play.md @@ -3,7 +3,7 @@ To expose endpoint as a [play-server](https://www.playframework.com/) first add the following dependencies: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-play-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-play-server" % "0.20.0-M10" ``` and (if you don't already depend on Play) diff --git a/generated-doc/out/server/vertx.md b/generated-doc/out/server/vertx.md index 2bce191208..96f2956067 100644 --- a/generated-doc/out/server/vertx.md +++ b/generated-doc/out/server/vertx.md @@ -8,7 +8,7 @@ Vert.x interpreter can be used with different effect systems (cats-effect, ZIO) Add the following dependency ```scala -"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M10" ``` to use this interpreter with `Future`. @@ -63,7 +63,7 @@ It's also possible to define an endpoint together with the server logic in a sin Add the following dependency ```scala -"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M10" "com.softwaremill.sttp.shared" %% "fs2" % "LatestVersion" ``` to use this interpreter with Cats Effect typeclasses. @@ -146,7 +146,7 @@ val attach = VertxCatsServerInterpreter(dispatcher).route(streamedResponse.serve Add the following dependency ```scala -"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-vertx-server" % "0.20.0-M10" "com.softwaremill.sttp.shared" %% "zio" % "LatestVersion" ``` diff --git a/generated-doc/out/server/zio-http4s.md b/generated-doc/out/server/zio-http4s.md index 6a54d155be..c0641d3f00 100644 --- a/generated-doc/out/server/zio-http4s.md +++ b/generated-doc/out/server/zio-http4s.md @@ -9,13 +9,13 @@ The `*-zio` modules depend on ZIO 2.x. For ZIO 1.x support, use modules with the You'll need the following dependency for the `ZServerEndpoint` type alias and helper classes: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-zio" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-zio" % "0.20.0-M10" ``` or just add the zio-http4s integration which already depends on `tapir-zio`: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-zio-http4s-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-zio-http4s-server" % "0.20.0-M10" ``` Next, instead of the usual `import sttp.tapir._`, you should import (or extend the `ZTapir` trait, see [MyTapir](../mytapir.md)): diff --git a/generated-doc/out/server/ziohttp.md b/generated-doc/out/server/ziohttp.md index 4fd11af7e9..d4543b1576 100644 --- a/generated-doc/out/server/ziohttp.md +++ b/generated-doc/out/server/ziohttp.md @@ -9,13 +9,13 @@ The `*-zio` modules depend on ZIO 2.x. For ZIO 1.x support, use modules with the You'll need the following dependency for the `ZServerEndpoint` type alias and helper classes: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-zio" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-zio" % "0.20.0-M10" ``` or just add the zio-http integration which already depends on `tapir-zio`: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-zio-http-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-zio-http-server" % "0.20.0-M10" ``` Next, instead of the usual `import sttp.tapir._`, you should import (or extend the `ZTapir` trait, see [MyTapir](../mytapir.md)): diff --git a/generated-doc/out/testing.md b/generated-doc/out/testing.md index 930d7d9800..d86cd5e788 100644 --- a/generated-doc/out/testing.md +++ b/generated-doc/out/testing.md @@ -12,7 +12,7 @@ details on how the stub works). Add the dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-sttp-stub-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-sttp-stub-server" % "0.20.0-M10" ``` And the following imports: @@ -42,9 +42,10 @@ val e = sttp.tapir.endpoint Convert any endpoint to `SttpBackendStub`: ```scala +import sttp.client3.Identity import sttp.client3.monad.IdMonad -val backend = SttpBackendStub +val backend: SttpBackendStub[Identity, Any] = SttpBackendStub .apply(IdMonad) .whenRequestMatchesEndpoint(e) .thenSuccess(ResponseWrapper(1.0)) @@ -57,7 +58,7 @@ effect can be used): import sttp.client3.Identity import sttp.client3.monad.IdMonad -val anotherBackend = SttpBackendStub +val anotherBackend: SttpBackendStub[Identity, Any] = SttpBackendStub .apply(IdMonad) .whenRequestMatchesEndpointThenLogic(e.serverLogic[Identity](_ => Right(ResponseWrapper(1.0)))) ``` @@ -79,7 +80,7 @@ with [mock-server](https://www.mock-server.com/) Add the following dependency: ```scala -"com.softwaremill.sttp.tapir" %% "tapir-sttp-mock-server" % "0.20.0-M9" +"com.softwaremill.sttp.tapir" %% "tapir-sttp-mock-server" % "0.20.0-M10" ``` Imports: @@ -168,7 +169,7 @@ Results in: ```scala res.toString -// res2: String = "Set(GET /x, is shadowed by: GET /x /..., GET /x /y /x, is shadowed by: GET /x /...)" +// res2: String = "Set(GET /x /y /x, is shadowed by: GET /x /..., GET /x, is shadowed by: GET /x /...)" ``` Example 2: