Where communities thrive

  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
Repo info
  • Jul 28 18:57
    mbore assigned #1357
  • Jul 28 18:14
    adamw commented #1399
  • Jul 28 18:13
    adamw opened #1399
  • Jul 28 18:13

    adamw on infer-validator-encode-to-raw

    #1398: infer the encode-to-raw … (compare)

  • Jul 28 14:01

    mergify[bot] on master

    Update client3:akka-http-backen… Merge pull request #1397 from s… (compare)

  • Jul 28 14:01
    mergify[bot] closed #1397
  • Jul 28 13:40
    kamilkloch opened #1398
  • Jul 28 13:16
    mergify[bot] labeled #1397
  • Jul 28 13:15
    scala-steward opened #1397
  • Jul 28 08:52
    geirolz commented #1395
  • Jul 28 08:52
    geirolz closed #1395
  • Jul 28 08:52
    geirolz commented #1395
  • Jul 28 07:50
    geirolz closed #1383
  • Jul 28 07:49
    geirolz commented #1383
  • Jul 27 19:54

    mergify[bot] on master

    Update zio, zio-streams, zio-te… Merge pull request #1396 from s… (compare)

  • Jul 27 19:54
    mergify[bot] closed #1396
  • Jul 27 19:09
    mergify[bot] labeled #1396
  • Jul 27 19:08
    scala-steward opened #1396
  • Jul 27 15:59
    geirolz edited #1395
  • Jul 27 15:57
    geirolz opened #1395
Vladimir Bodnartchouk
Hello, i would like to use tapir with https://github.com/RustedBones/akka-http-metrics
is there a custom way to specify the path ? In my case i would like to declare an Endpoint but use pathLabeled directive to let akka-http-metrics create prometheus metrics.
1 reply
Denis Novac

Hi everyone. Is it possible to get schemaType for some T from ADT with schema? Something like this kind function perhaps (this one does not work)?


import sttp.tapir.{Schema, SchemaType}
import sttp.tapir.generic.{Derived, SchemaDerivation}

sealed trait Animal extends SchemaDerivation

object Animal extends SchemaDerivation {

  implicit val schema = Schema.derived[Animal]

  final case class Cat(name: String) extends Animal
  final case class Dog(name: String) extends Animal
  final case class Horse(name: String, speed: Float) extends Animal


def kind[T <: Animal](t: T): SchemaType = Schema.derived[T].schemaType
3 replies
Denis Novac

Hi everyone. Is it possible to get schemaType for some T from ADT with schema? Something like this kind function perhaps (this one does not work)?

Also it seems that Schema.derived is enough. I though it takes some implicits from SchemaDerivation. What is the difference between Schema.derived and SchemaDerivation mixing?

5 replies

Hi, my errors code looks like this.

sealed trait ApiError { self =>

  val code = self match {
    case ApiError.UnauthorizedError(_) => 401
    case ApiError.NotFoundError(_) => 404
    case ApiError.BadRequestError(_) => 400


object ApiError {

  case class UnauthorizedError(reason: String) extends ApiError

  case class NotFoundError(message: String) extends ApiError

  case class BadRequestError(reason: String) extends ApiError


I'm getting this result

HTTP/1.1 400 BadRequest
Content-Length: 14
Content-Type: application/json
Date: Thu, 14 Jan 2021 18:03:45 GMT
Server: akka-http/10.2.2

    "reason": ""

Is there a way to properly serialize inherited parameters? Do I have to create a custom decoder and encoder?

31 replies
Denis Novac
Hi everyone. Getting this error while migrating to 0.17:
Cause: java.lang.IllegalArgumentException: Validator reference is already set to Product(Map(filter -> sttp.tapir.generic.internal.SchemaMagnoliaDerivation$$anon$1@7442d39b))!
at sttp.tapir.Validator$Ref.set(Validator.scala:228)
at sttp.tapir.generic.internal.SchemaMagnoliaDerivation.$anonfun$combine$2(SchemaMagnoliaDerivation.scala:33)
at scala.Option.foreach(Option.scala:407)
at sttp.tapir.generic.internal.SchemaMagnoliaDerivation.$anonfun$combine$1(SchemaMagnoliaDerivation.scala:33)
at sttp.tapir.generic.internal.SchemaMagnoliaDerivation.withProgressCache(SchemaMagnoliaDerivation.scala:76)
at sttp.tapir.generic.internal.SchemaMagnoliaDerivation.combine(SchemaMagnoliaDerivation.scala:16)
at sttp.tapir.generic.internal.SchemaMagnoliaDerivation.combine$(SchemaMagnoliaDerivation.scala:15)
at sttp.tapir.Schema$.combine(Schema.scala:99)
I guess somewhere i have two schemas for my type or something?
2 replies
I just write val x = MyType(...) and this happens in runtime. No compile errors
Denis Novac
Actually MyType does not even have a schema, it is only for internal usage.
Denis Novac

Hi everyone. I just noticed that all my docs routes have index.html page with Swagger Petstore (default Swagger example). E.g.:

My OpenAPI documentation: localhost:8080/api/v1/docs
Swagger Petstore: localhost:8080/api/v1/docs/index.html

And so on every controller.

How do you disable it?

1 reply
Morning all, just trying to use tapir for the first time (with http4s) and I've come a bit unstuck handling errors. In my current code base, I have a function along the lines of def handleResponse[Resp: Encoder](resp: Either[MyError, Resp]): IO[Response[IO]] = ... which I use to handle different instances of MyError (it's a trait with some case classes) and transform them into Responses. I can't figure out how to achieve this in tapir. I've had a look at the documentation, but neither errorOut nor the approach to just recover from the errors quite fits. Any advice very much appreciated
2 replies
(The problem appears to be that Http4sServerInterpreter.toRoutes handles the mapping from Either[MyError, Resp] to IO[Response[IO]] automatically)
Josip Grgurica
8 replies
Matthew Tovbin
Hi folks. Is there a way to attach documentation to request/response types for the API, e.g. case class Book(/*This is a title of the book*/ title: String)?
6 replies
Gopal Shah

Hi all, I am looking to have an api with query parameters having defaults values, similar to https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/parameter-directives/parameters.html


Does Tapir support this?

5 replies
Thijs Broersen
I have an issue with using and endpoint as a client. The endpoint returns a 307 http status code (server encoding works fine) but I get a decoding failure. When I remove the 307 status, this line .out(statusCode(StatusCode.TemporaryRedirect)), the client can correctly decode. Should I do this differently? Is this a bug?
Thijs Broersen
I suspect the client is following the redirect ..
Thijs Broersen
Tried set false to any redirect, does not help. I only see exhausted input as decode result error. Doing a manual request on the API I do get what I expect.
Thijs Broersen
building the request by hand (disabling redirects) does work basicRequest.followRedirects(false)
2 replies
Srepfler Srdan
where are we with the asyncapi work? I think I've found an interesting use case in Lagom, for example they have some servicec endpoints which are stream on websocket but they also generate a kafka stream for the events that are generated. It would be really cool if one Tapir definition would generate both the Play endpoints (stream and non stream) but also the kafka events. In the Lagom API also there's this compositional step Command -> Event which is also interesting
2 replies
Assen Kolov
How can I access the hashtag value in a request like GET /cognito/login#token=123&type=Bearer ? I don't have much control over the request, I want to handle it as it is. The hashtag value seems to be lost in the ServerRequest instance.
Assen Kolov
Aha: fragment (#) is not sent to the server at all, must be handled in browser :-)
Pouria Mellati
Hi all, is there a way to specify a namespaced name for schema objects? For instance, if endpoint one returns my.scala.packageone.User and endpoint two returns my.scala.packagetwo.User, how can I ensure that the two versions of User are represented with correct package / namespace names?
3 replies
Pascal Danek

Hello guys - bravo for this extraordinary project it has changed my life in coding Rest APIs in Scala :) I come here because I have a problem with having Scala built in enumerations schema in my openapi doc.

Here is a code snippet that reproduces the issue (mainly coming fro the documentation):

import sttp.tapir._
import sttp.tapir.generic.auto._
import sttp.tapir.json.circe.jsonBody
import io.circe.generic.auto._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter
import sttp.tapir.openapi.circe.yaml._

trait EnumHelper { e: Enumeration =>
  import io.circe._

  implicit val enumDecoder: Decoder[e.Value] = Decoder.decodeEnumeration(e)
  implicit val enumEncoder: Encoder[e.Value] = Encoder.encodeEnumeration(e)

  implicit val schemaForEnum: Schema[e.Value]       = Schema.string
  implicit def validatorForEnum: Validator[e.Value] = Validator.`enum`(e.values.toList, v => Option(v))

object Color extends Enumeration with EnumHelper {
  type Color = Value
  val Blue = Value("blue")
  val Red  = Value("red")

case class Drawing(color: Color.Value)

val ep = endpoint.in(jsonBody[Drawing])

Now I generate the openapi documentation with: println(OpenAPIDocsInterpreter.toOpenAPI(ep, "My Project", "1.0").toYaml)

And here is what I get:

openapi: 3.0.3
  title: My Project
  version: '1.0'
      operationId: getRoot
              $ref: '#/components/schemas/Drawing'
        required: true
          description: ''
      - color
      type: object
          type: string

So as you can see, no enumeration values.

Do you have an idea about what's going on here ?

Thanks in advance for your help.

7 replies
Pascal Danek

Also I have a second problem with the use of serverLogic on my endpoints. The compiler complains about a type issue, but I guess it is a problem of inference maybe you can help me there. Here is how to reproduce:

import io.circe.generic.auto._
import monix.eval.Task
import sttp.tapir._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter
import sttp.tapir.generic.auto._
import sttp.tapir.json.circe.jsonBody

case class Foo(value: String)

val ep1 = endpoint.out(stringBody).in(jsonBody[Foo]).serverLogic[Task] { _ =>

val ep2 = endpoint.out(stringBody).in("foo")

val eps = Seq(ep1, ep2)

println(OpenAPIDocsInterpreter.toOpenAPI(eps, "My Project", "1.0").toYaml)
overloaded method toOpenAPI with alternatives:
(es: Iterable[sttp.tapir.Endpoint[_, _, _, _]],title: String,version: String)(implicit options: sttp.tapir.docs.openapi.OpenAPIDocsOptions): sttp.tapir.openapi.OpenAPI <and>
[I, E, O, S, F[_]](se: sttp.tapir.server.ServerEndpoint[I,E,O,S,F], title: String, version: String)(implicit options: sttp.tapir.docs.openapi.OpenAPIDocsOptions): sttp.tapir.openapi.OpenAPI <and>
[I, E, O, S](e: sttp.tapir.Endpoint[I,E,O,S], title: String, version: String)(implicit options: sttp.tapir.docs.openapi.OpenAPIDocsOptions): sttp.tapir.openapi.OpenAPI
cannot be applied to (Seq[Product with sttp.tapir.EndpointInfoOps[_ >: Unit with Foo, Unit, String, Any] with sttp.tapir.EndpointMetaOps[_ >: Unit with Foo, Unit, String, Any] with java.io.Serializable], String, String)
println(OpenAPIDocsInterpreter.toOpenAPI(eps, "My Project", "1.0").toYaml)

Note that as soon as I am starting to use serverLogic I cannot concatenate anymore my endpoints. The compiler complains:

type mismatch;
 found   : Seq[sttp.tapir.Endpoint[_ >: Unit with String, (ilogyou.web.endpoints.EndpointError, sttp.model.StatusCode), _ >: Unit with ilogyou.modules.LoginResponse, Any]]
 required: scala.collection.IterableOnce[Product with sttp.tapir.EndpointInfoOps[...

Thanks again for your help.

3 replies
Oleksandr Shtykhno

hi, I need to use

Endpoint[SomeCaseClass, SomeErrorInfo, ZioStreams.BinaryStream, ZioStreams]

but it looks like integration for ZIO streams and Http4s is not implemented yet, I would appreciate any tip to the right direction

4 replies
Pascal Mengelt

Hi, I use Tapir to generate Open API. I could not figure out how to set a default value for a path variable.
This is my path:

.in(("process-definition" / "key" / path[String]("processDefinitionKey") / "tenant-id" / path[String]("tenant-id") / "execute"))

The output should be like:

      - name: tenant-id
        in: path
        required: true
          type: string
          default: myTenant
4 replies

Hi there! I have such a situation (input data is in url-encoded format):

case class Foo(foo: Option[String])
case class Bar(bar: Option[Foo])

implicit def fooCodec: Codec[Option[String], Foo, CodecFormat.TextPlain] =
  Codec.option[String, String, CodecFormat.TextPlain]

def func: Endpoint[Bar, Unit, String, Any] = endpoint

And compiler says to me the next:

exception during macro expansion:
scala.reflect.macros.TypecheckException: Cannot find a codec between types: List[String] and Option[Foo], formatted as: sttp.tapir.CodecFormat.TextPlain.
Did you define a codec for: Option[Foo]?
Did you import the codecs for: sttp.tapir.CodecFormat.TextPlain?

What did I do wrong?

2 replies

bauerflo @bauerflo 11:34
Hi! I believe there might be something wrong with the tapir backend stub tests
my endpoint looks like this

val destinationEndpoint = endpoint

val postDestination = destinationEndpoint.post
.in("companies" / path[TenantId] / "destinations")

and my stubs:

.apply[Future, Capabilities]
.whenInputMatches(Endpoints.postDestination)(_._4 == destination)

my destination definitely goes in here (in debugging)

.apply((token, traceId, tenantId, destination))

the input in the stub however takes all parameters correctly but the destination is null (so, the stub works if I match on _._4 == null)

I noticed in debugging that req below contains all input parameters and the last one is a StringBody(...) containing my (correctly serialized) destination object as json

def whenInputMatchesI, E, O(inputMatcher: I => Boolean): TypeAwareWhenRequest[I, E, O] = {
new TypeAwareWhenRequest(
new stub.WhenRequest(req =>
DecodeInputs(endpoint.input, new SttpDecodeInputs(req)) match {
case _: DecodeInputsResult.Failure => false

however it checks out in DecodeInputsResult.Failure

4 replies
Pascal Danek
Hello guys, I am desperately trying to build a ServerEndpoint returning a fs2 stream of json objects on http4s. Can someone point me to some examples based on the latest tapir version ? The string based doc examples does not allow me to understand how I am supposed to proceed. There are also conflicting examples on the internet giving different streamBody definitions. Lets say I have a case class Person(name: String), a service def getPersons: fs2.Stream[Task, Person]. What is the corresponding .out(streamBody(???)) and how in the serverLogic i can transform this type into something accepted by Tapir on http4s ? Thanks for any help !
5 replies
Hi @adamw Do you plan some work regarding to processing multipart files in stream matter?
My case is next, I tring to process big csv file in reactive-like manner and now I oparsing multipart body manually. So it would be great to add such possibility. What do you think about this?
1 reply

Hello, I'm trying to define a custom schema mostly by hand, but the generated OpenAPI doesn't show the enum values for my field:

implicit val myResponseSchema: Schema[MyResponse] = Schema(
      FieldName("someEnum") -> schemaForEnumEntry[SomeEnum]
        .description("A description of the enum")
      FieldName("someNumber") -> Schema.schemaForDouble
  description = Some("Custom description of the response")

I'm using the tapir-enumeratum integration. If I stick to auto derivation, it works. If I compare both auto and my own schema objects, they look similar (save for the description and example). I'm a bit puzzled.

Impressive work with tapir
Was wondering if Schema works well with polymorphic and higher kinded case classes?
1 reply
Mateusz Wójcik

Hi guys, I'm playing with custom schema, I wanted to add additional validations to some nested NonEmptyList (e.g. max size):

case class Wrapper(items: NonEmptyList[String])

    implicit val customWrapperSchema: Schema[Wrapper] = implicitly[Derived[Schema[Wrapper]]]
      .modify(_.items)(_.validate(Validator.maxSize[String, List](1).contramap(_.toList)).description("Some description"))

    val yaml = OpenAPIDocsInterpreter.toOpenAPI(endpoint.out(jsonBody[Wrapper]), Info("Fruits", "1.0")).toYaml

but this max size gets ignored:

      - items
      type: object
          type: array
            type: string
          description: Some description
          minItems: 1

am I doing something wrong or is it some kind of bug?

3 replies
Roman Makurin
hello guys, i have a strange question, but is possible on tapir level to modify response(put headers for example) - something like .in(extractFromRequest()) ?
Roman Makurin

i have code something like this

    .in("api" / "v1" / "do")
    .serverLogicForCurrentRecoverErrors((authBridge.auth _).tupled.andThen(handleError[F, AuthInfo[F]]))
    .serverLogicRecoverErrors(service.doWork.andThen(handleError[F, Json]))

but now i need to add headers to response back, what is the prefered way of doing this? I understand how to extract all needed info from request, but how to put back any calculated header?

Im in stuck now :)

1 reply
Mateusz Wójcik
Is there any way to add a section in OpenAPI for 400 Bad Request error which is by default returned for validation errors? My endpoint by itself does not have any error output, and I'd like to document in OpenAPI that 400 is returned when this and that validation on schema fails.
12 replies
Gabriel Asman

Hello, I've been working a Tapir API solution for my API and I find myself having a small issue. I had to define a custom schema for a few of my classes where auto-generation wouldn't suffice. But then I noticed that the validations my class's fields (in my case 1 field, an enum) was not showing up in the documentation. After going in deep with the debugger I found the place where that information is "lost"

On this line, rather the recursive call to apply being passed fieldSchema.validator as I might've expected, it instead uses the fieldValidatormethod to construct a new validator from the "parent"'s (current object's) validator. My first question is why is this so? My next question is what do I need to change in the parent validator in order to get my validator where I want it to. Looking at the logic of fieldValidator it looks like an Enum validator like the one I did would get discarded during the collect{ ... } pattern match.

                fieldName.encodedName -> apply(TypeData(fieldSchema, fieldValidator(typeData.validator, fieldName.name)))


Let me know if this makes sense and thanks in advance for your time!

Ooh, just scrolled up a bit and might be the same issue as @matwojcik 's softwaremill/tapir#1047
Thijs Broersen
Is there any way I can capture paths (arbitrary dept) until a certain path/pattern matches?
Thijs Broersen
e.g. endpoint.in(paths).in("fixed-path-key") client request builds a correct path from an arbitrary list of strings and ends with 'fixed-path-key'. But the backend endpoint never matches the request.
10 replies

Hello, is it possible to upload (stream) files of any size with arbitrary content type? The example on the website (https://tapir.softwaremill.com/en/latest/endpoint/streaming.html) doesn't work for me:

endpoint.out(streamBody(AkkaStreams)(Schema(Schema.derived[List[Person]].schemaType), CodecFormat.Json()))

In play2, there is the HttpEntity.Chunked type:

      def contentType = file.contentType.getOrElse("application/octet-stream")
      def chunks = GridFSStreams(gfs).source(file).map(HttpChunk.Chunk(_))

        header = ResponseHeader(OK),
        body = HttpEntity.Chunked(chunks, Some(contentType))

But I can not replicate the functionality on tapir side since streamBody requires a fixed codec format. Can I somehow avoid specifying the codec format or maybe at least specify a list of codec types?

13 replies
Gabriel Asman
MatchType derivation seems to not work for Sets ? Rather confusing as it seems like it should be based on Magnolia examples and stuff? Tried to dive into the Magnolia code to understand where it's supposed to be derived (or where the List equivalent is) but it was too complicated for me. Anyone encountered this/have a work around (other than just switching to list, which I might end up doing)
  final case class X(a: Set[String])
  val w                                        = MatchType.gen[X]
2 replies
magnolia: could not find MatchType.Typeclass for type Set[String]
    in parameter 'a' of product type TapirRoutes.this.X

  val w                                        = MatchType.gen[X]
Gabriel Asman
Another one from me - is there any way documentation for built for stream (input) bodies?
This is what I have right now to set up the streaming endpoint (using fs2-circe), I think it "works" but the documentation produced is not very useful. Is there a way to incorporate the actual schema of MyType in the documentation too?
      .in(streamBody(Fs2Streams[IO])(Schema.binary, CodecFormat.Json(), StandardCharsets.UTF_8.some))
          .through(decoder[IO, MyType])
2 replies
In play, there exists RemoteConnection, as part as the RequestHeader class. Is there a comparable way to get access to the raw request in tapir? I would need the IP address and the protocol (http, https) of the request for example.
2 replies
Blaž Marinović
hi, is it possible to render Cats' NonEmptyList[T] as regular List[T] in OpenApi generator? Currently, for Nel[Int], I'm getting it as:

      - head
      type: object
          type: integer
          type: array
            type: integer
1 reply
@bmarinovic: The following snippet should do that (have no good setup for testing right now, but works fine with very similar code for NonEmptyMap):
  implicit def schemaForNonEmptyList[V](implicit s: Schema[List[V]]): Schema[NonEmptyList[V]] =
Łukasz Biały
hi, I'm trying to add tracing and metrics to an akka-http based server app that uses tapir. is there any established way to do this? I've tried wrapping resulting Route but that doesn't really work if the route doesn't match (timers start before route is evaluated). I have therefore moved my monitoring code to wrap the function passed to serverLogic method and this provides useful metrics but I can't gather data such as the resulting http code or the actual http path from hostname. Any ideas?
8 replies