Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • May 11 14:00
    mbore synchronize #1225
  • May 11 14:00

    mbore on adapt-validator-macros

    handle enum with parameters (compare)

  • May 11 12:32
    rojekp synchronize #1223
  • May 11 12:32

    rojekp on openapi-3.1.0-support-v2

    Extended model of Reference - a… (compare)

  • May 11 12:19
    mbore review_requested #1225
  • May 11 12:19
    mbore opened #1225
  • May 11 12:18

    mbore on adapt-validator-macros

    Add validator for coproduct enu… Enum validator for scala 3 add enumeration info. (compare)

  • May 11 09:59
    adamw commented #1154
  • May 11 09:07
    catostrophe commented #1154
  • May 11 09:07
    catostrophe commented #1154
  • May 11 09:05
    catostrophe commented #1154
  • May 10 18:44
    scala-steward opened #1224
  • May 10 13:08
    brbrown25 commented #1154
  • May 10 12:24
    adamw commented #1154
  • May 10 11:52
    brbrown25 commented #1154
  • May 10 09:40

    mergify[bot] on adapt-mapTo

    (compare)

  • May 10 09:40
    adamw synchronize #1204
  • May 10 09:40

    adamw on scala3

    mapTo for Scala 3 Add add tests for malformed tar… Merge pull request #1220 from s… (compare)

  • May 10 09:40
    adamw closed #1220
  • May 10 09:24
    mbore edited #1220
johnhungerford
@johnhungerford
I get the same result when I define a schema manually
johnhungerford
@johnhungerford
Looks like my issue is addressed here: softwaremill/tapir#1051
3 replies
Dmitriy Kovalenko
@dkovalenko
Hi all. Is there any way to map input from query params into case class with more than 22 fields?
1 reply
Maybe some kind of intermediate map/list from tuple? I don't want to split my domain class to 2-3 classes just to make tapir work.
Jonathan Neufeld
@jonathan-neufeld-asurion
Hello, how does one express documentation for specific status return codes that have no body? I made a helper like this: EndpointIO.Empty(Codec.idPlain(), EndpointIO.Info.empty).map(_ => obj)(_ => ()).description("my description") but it doesn't work and isn't documented.
1 reply
heksesang
@heksenlied:matrix.org
[m]
Is it possible to define multiple CodecFormat for the output of an endpoint, in the case that it might return one of multiple content-types depending on some query parameters or headers?
1 reply
Gilad Hoch
@hochgi

Hi,
I'm using tapir, and really liking it so far. But there's something I find a bit odd in the default behaviour of endpoint input, but maybe I'm not using it correctly?
Anyway, the usecase is simple. consider some simple endpoint like:

val getUsers: Endpoint[Int, String, String, Any] = {
  val userId = path[Int].description("The user ID is a 32-bit signed integer")
  endpoint
    .name("get user")
    .get
    .in("api" / "users" / userId)
    .errorOut(stringBody)
    .out(stringBody)
}

I would expect that a call like: GET <host>/api/users/foo would result with something like:
400 BadRequest : 'foo' is not a valid Int
instead we get:
500 Internal Server Error : There was an internal server error.

Looking at the code, I see that path has a context bound for a codec, which I guess is always this:

implicit val int: Codec[String, Int, TextPlain] = stringCodec[Int](_.toInt).schema(Schema.schemaForInt)

and in the implementation, it's just string codec mapped with _.toInt, leaving the validator as Validator.pass.

So this seems a bit weird to me, since clearly what we want in such a case is to validate the primitives properly, thus returning 400, and not 500 in case of invalid input.

  1. Is there anything I missed? Is there an easy fix?
  2. If not, would you like me to open an issue for that?

Thanks!

13 replies
Doug Clinton
@DougC
I have a case class for which I have a custom circe encoder that adds an extra field to the generated json. How can I modify the schema to add a description of the extra field?
5 replies
Thijs Broersen
@ThijsBroersen
I upgraded Tapir from 0.17.9 to 0.17.19 and now RedocHttp4s is broken. I get a 308 when I want to view the rendered docs. Could not find any related (bug-)ticket in github. I see some changes in the source-code but cannot find any migration instructions. Anyone got the same issue?
Thijs Broersen
@ThijsBroersen
turns out contextPath cannot be Nil or an empty String
6 replies
also RedocHttp4s and SwaggerHttp4s have different implementations (e.g. contextPath is a List[String] for the first and String for the latter)
sken
@sken77
would adding a server interpreter with zio-http be considered?
i know we have zio-http4s already and zio-http is not official zio but 3rd party, although is endorsed by zio devs
sken
@sken77
is there a guide to write your own server interpeter. what is the interface?
3 replies
Mark Hammons
@markehammons
how difficult would it be to add custom authentication and one-of authentication to tapir?
is it on the roadmap at all at the moment? I am wanting to adopt tapir for a project, but our auth needs (one-of 3 possible auths must be met, one of the auths is an non-conforming "oauth") block us actually transitioning to tapir
15 replies
Mathieu Prevel
@mprevel
Hi guys,
I am using tapir in a multi modules project (frontend, backend, shared).
If my understanding is good I should define the endpoints in the shared module, the server interpreter in the backend module and the client interpreter in the frontend (or better, the shared module).
My models also use newtype and so my project uses tapir-newtype integration.
Nonetheless there is no release of tapir-newtype for scala.js
Is there a limitation about publishing this artifact for scala.js ?
5 replies
mcallisto
@mcallisto
Hi @mprevel I would like to use tapir on a scala.js frontend as well, is there any example you could point to? After reading https://tapir.softwaremill.com/en/latest/client/sttp.html I have been able to send a request using the FetchBackend. But how to implement endpoints? I have added to my dependencies
"com.softwaremill.sttp.tapir" %%% "tapir-sttp-client" % "0.18.0-M2" but I am struggling to find a way.
mcallisto
@mcallisto
I might be mistaken, but looking at the errors it seems that one of the issues is that part oftapir-sttp-client is relying on methods that don't have a counterpart in scala.js, such as java.time.Instant.atZone(java.time.ZoneId)java.time.ZonedDateTime or java.time.LocalTime.parse(java.lang.CharSequence)java.time.LocalTime. Has anyone experience on Tapir in scala.js?
7 replies
Vitalii
@vitaliihonta
Hi there! Did anybody had a chance to look at my PR with mock-server integration? softwaremill/tapir#1097 I would appreciate someone can join the discussion about testing so that I can go forward
1 reply
Vadim Agishev
@Chicker

Hi there!

Could you answer me, why the type ZServerEndpoint[R, I, E, O] = ServerEndpoint[I, E, O, Any, RIO[R, *]] is coupled to RIO, where error type is Throwable instead of using more flexible ZIO[R, E, *]?

I have a problem, I have an endpoint of ServerEndpoint[(String, Unit), ApiError, String, Any, ZIO[Any, ApiError, *]] type where type parameter E is the my custom type ApiError <: Throwable and I can't use ZHttp4sServerInterpreter because of type mismatch error: ZIO[Any, ApiError, ] can't be used in RIO[Any, ] context.
Thanks in advance!

6 replies
Martin Allaire
@mallaire77
Howdy guys, has .toDirective been removed or migrated as an option from AkkaHttpServerInterpreter in v0.18?
2 replies
vonchav
@voonchav_gitlab

Hi Adam, I'm excited about a new version of Tapir. I upgraded Tapir to 0.18 M4. Minor changes mostly, though I wanted to bring up a few items before opening tickets.

  1. The respond method in sttp.tapir.server.interceptor.decodefailure.DefaultDecodeFailureHandler, has these two parameters, badRequestOnPathErrorIfPathShapeMatches & badRequestOnPathInvalidIfPathShapeMatches. I don't think their semantics have changed in the new version. By setting both to true, I'm expecting any mismatch in the shape of the URL should result a 400-BadRequest. However, currently those tests that were designed to test this behavior in my test suites are failing because the returning status code is now 404-NotFound. I can see in the code that it seems to return 400-BadRequest (Some(onlyStatus(StatusCode.BadRequest))) but I'd like to confirm with you if this is a bug.

  2. In the new sttp.tapir.server.http4s.Http4sServerOptions, it provides Log.defaultServerLog as the default implementation. My problem with the current impl is that it doesn't allow me to override the logAllDecodeFailures parameter in the DefaultServerLog constructor. I have this flag as an app setting so that I can turn it on for troubleshooting purpose. The current impl of Log.defaultServerLog returns ServerLog[F[Unit]], so I can't call copy to set the logAllDecodeFailures parameter myself. I can submit a PR for this but if you think it's trivial enough that you can squeeze in a fix in the next release, I'd leave it to you then.

  3. Also, for the implementation of customInterceptors in sttp.tapir.server.http4s.Http4sServerOptions, right now the implementation uses ExecutionContext.Implicits.global. I wonder if it makes sense to make it a parameter so it can be passed in from call sites. With the current implementation, in order to provide a different executor, the only choice for me as a user is to re-implement customInterceptors myself.

Please let me know your thoughts on these. Thank you again for all your hard work for this amazing lib. Looking forward to the official release.

18 replies
allawala
@allawala

Hi, I need some help. I am upgrading Tapir from v 0.16.16 to 0.17.19. My http routes are based off this github project https://github.com/saraiva132/zio-cats-backend from the zio website resources section. In short the old routes are using the toRoutesR variant where i was passing the environment in via URIO eg

object ShortenRoutes {
    val routes: URIO[BitlyEnv, HttpRoutes[Task]] =
        ShortenApi.getShortenEndpoint.toRoutesR {
          case (reqCtx, url) =>
            Bitly.shortenUrl(url).mapToClientError(reqCtx)
        }

}

I am trying to convert it to something like

object ShortenRoutes {
    val routes: HttpRoutes[RIO[BitlyEnv, *]] = ZHttp4sServerInterpreter.from(ShortenApi.getShortenEndpoint) { req =>
        val (reqCtx, url) = req
        Bitly.shortenUrl(url).mapToClientError(reqCtx)
      }.toRoutes
}

I am using http4s server where previously i had

  private val appRoutes: URIO[AppEnv, HttpApp[Task]] =
    for {
      healthRoutes  <- HealthRoutes.routes
      shortenRoutes <- ShortenRoutes.routes
      docsRoutes     = new SwaggerHttp4s(yaml).routes[Task]
    } yield {
      (healthRoutes <+> shortenRoutes <+> docsRoutes).orNotFound
    }

and in my BlazeServerBuilder I had

    for {
      app                            <- appRoutes
      config                         <- getConfig[HttpServerConfig]
      implicit0(rts: Runtime[Clock]) <- ZIO.runtime[Clock]
      ec                             <- ZIO.descriptor.map(_.executor.asEC)
      _ <-
        BlazeServerBuilder[Task](ec)
          .bindHttp(config.port, config.host)
          .withConnectorPoolSize(config.poolSize)
          .withIdleTimeout(config.idleTimeout.asScala)
          .withResponseHeaderTimeout(config.responseHeaderTimeout.asScala)
          .withoutBanner
          .withHttpApp(app)
          .serve
          .compile
          .drain
    } yield ()

The new code looks like

....
     BlazeServerBuilder[RIO[BitlyEnv, *]](ec)
....
    .withHttpApp(Router("/" -> (ShortenRoutes.routes <+> HealthRoutes.routes <+> new SwaggerHttp4s(yaml).routes)).orNotFound)

where BitlyEnv contains Clock

The ShortenRoutes takes BitlyEnv as the environment, where as the HealthRoutes only takes Clock since its method signature is HttpRoutes[RIO[Clock, *]].

The compiler complains about type mismatches unless i pass in the BitlyEnv to the HealthRoute as well.

New to zio/http4s and pure functional programming so I am struggling to figure out what I am doing wrong or how to have multiple routes take in different environments and make the compiler happy. Any help would be appreciated. Again , i cant really share all the code, but as mentioned, its based on the github example above specifically the http.routes package

12 replies
Edvin Lundberg
@Edvin-san
Hi, I have a server endpoint defined with tapir. The logic simply calls another service with sttp client. How could I forward the HttpError from the sttp client as the tapir endpoint error?
4 replies
ex0ns
@ex0ns

Hello, I was playing with tapir a bit and I struggle a bit with the type involved in route definition.
I'm currently using this code to create a ZLayer from my services

  // type Routes[T] = ZIO[Clock, Throwable, T]
  // type ZRoutes   = HttpRoutes[Routes]
  def swaggerRoutes: ZRoutes =
    new SwaggerHttp4s(swaggerDefinition, contextPath = "docs").routes[Routes]

  def routes: URLayer[Has[GameService], Has[ZRoutes]] =
    ZLayer.fromService[GameService, ZRoutes] { gameService =>
      val r = ZHttp4sServerInterpreter
        .from(
          List(
            endpoints.startGame.zServerLogic(_ => gameService.startGame()),
          )
        )
        .toRoutes
      r <+> swaggerRoutes
    }

And I wanted to change my code to use method from gameService's companion object, instead of using the ZLayer.fromServices so I ended up doing that

type RoutesTest[T] = ZIO[Has[GameService] with Has[Clock.Service], Throwable, T]
  type FinalRoutes   = HttpRoutes[RoutesTest]
  def routes2: FinalRoutes = {
    val r: HttpRoutes[RoutesTest] = ZHttp4sServerInterpreter
      .from[Has[GameService]](
        List(
          endpoints.startGame.zServerLogic(_ => GameService.startGame())
        )
      )
      .toRoutes
    r <+>
      new SwaggerHttp4s(swaggerDefinition, contextPath = "docs").routes[RoutesTest]
  }

But I don't really like working with those HttpRoutes and Kleisli. Is there a way for me to create a ZIO layer from this ? Or is it not the way it's supposed to work, and having a ZLayer around those HttpRoutes is not recommended

4 replies
Andy Czerwonka
@andyczerwonka

about to take on an upgrade from 0.17.0-M9, so wondering if someone can point me to key changes and/or a migration strategy? Just looking at the docs and comparing it to my imports, looks like some significant breaking changes. E.g, my imports

object MyTapir
    extends Tapir
    with TapirAkkaHttpServer
    with TapirOpenAPICirceYaml
    with TapirAliases
    with ValidatorDerivation
    with SchemaDerivation {

I see the TapirAkkaHttpServer import has changed, I'm curious about ValidatorDerivation and others. I also see that someone contributed Json4s support, so I'll need to bring that in.

2 replies
Andy Czerwonka
@andyczerwonka

Looks like a few significant breaking changes. In reverse order:

  1. https://github.com/softwaremill/tapir/releases/tag/v0.18.0-M1
  2. https://github.com/softwaremill/tapir/releases/tag/v0.17.0
  3. https://github.com/softwaremill/tapir/releases/tag/v0.17.0-M9

If there is anything else I should look out for, please let me know.

1 reply
ex0ns
@ex0ns

Is there a way to combine EndpointInput using or instand of and. My goal would be to support either
path/to/session/XXXXX or a custom header x-custom-session = XXXXX
I've defined those two EndpointInput:

  val sessionHeader: EndpointInput[UUID]    = header[UUID]("session")
  val sessionHeaderUrl: EndpointInput[UUID] = path[UUID]("x-custom-session")

But I don't know how to combine them

2 replies
balthz
@balthz

Hi there! I have a question regarding testing. Often, I find myself in the situation where I don't just have an Endpoint but a ServerEndpoint with a bit of logic that I'd like to test. Example:

def twice(logic: IO[String]): ServerEndpoint[Unit, String, String, Any, IO] =
    endpoint.get
      .in("foo")
      .out(stringBody)
      .errorOut(stringBody) // (*)
      .serverLogic { _ =>
        logic
          .map(s => s"$s$s")
          .attempt
          .map {
            case Left(throwable) => Left(throwable.getMessage)
            case Right(s)        => Right(s)
          }
      }

The SttpBackendStub (from the docs) is super helpful to test just the first part (i.e., up to (*)) and of course, I could test the logic inside .serverLogic separately, by factoring it out into a function.

However, if I want a more end-to-end type test, is there an easy way to do this?

Something like (I'm phantasizing here):

val backend = SttpBackendStub.forServerEndpoint(twice(IO("bar")))
client3.basicRequest
        .get(uri"http://abc.xyz/foo")
        .send(backend)
        .body should equal(Right("""barbar"""))

?

3 replies
Adam Warski
@adamw

Survey time! Which authentication features are you using and how? What are you missing! Let us know to help shape tapir moving forward :)

https://forms.gle/vJ7soj9JL23JTtpC8

Thank you!

2 replies
Loránd Szakács
@lorandszakacs
I looked on maven for the: tapir-http4s-client, and no such artifact seems to exist. Not even something similar. Am I missing something?
https://tapir.softwaremill.com/en/latest/client/http4s.html#
1 reply
mcallisto
@mcallisto
This is not really about Tapir but more on a specific implementation.
I have a Play backend where authentication is done using the Silhouette Play library. So there is a SecuredAction instead of a Play action.
I can perfectly integrate Tapir like done for example in https://github.com/gaeljw/tapir-play-sample.
But I am struggling to place the Silhouette validation bit into the authentication function called by the partial server endpoint.
Has anyone already used Tapir with Play + Silhouette and can give me some hints?
1 reply
Denis Novac
@DenisNovac
Hi everyone. I found this issue on the GitHub about Dotty support: softwaremill/tapir#852 . I am wondering why does Tapir need to wait Magnolia update now when Scala 3 can do recursive derivation out of the box?
heksesang
@heksenlied:matrix.org
[m]
@DenisNovac: I guess it's not necessary to wait, though I did see magnolia has merged a PR for Scala 3 support now. So a question is if one wants to rely on magnolia, or just port all the magnolia-stuff to the native tooling for derivation. I do hope tapir will be ready for Scala 3 soon, it's the one library I am waiting for to make the jump to complete Scala 3 build in a project I am working on.
Denis Novac
@DenisNovac
@heksenlied:matrix.org they have closed something, but there is no merge and Scala 3 support yet as far as i see: ghostdogpr/caliban#847
I am not sure why the PR was listed as closed, as all the commits are in master.
They haven't made a release yet, though I do hope they'll make one soon. That should speed up the porting of everything that relies on magnolia.
heksesang
@heksenlied:matrix.org
[m]
Magnolia for Scala 3 might be released in a few days hopefully – once that is done, it shouldn't be that much work moving tapir onto Scala 3, I imagine.
heksesang
@heksenlied:matrix.org
[m]
Anyone familiar enough with the project that they can help me figure out what I need to change in the build.sbt to try compile the zio integrations for 3.0.0-RC1 and publish them to an artifactory instance?
1 reply
Adam Warski
@adamw
@heksenlied:matrix.org there's a couple of macros (I think all of them Schema-related) that need to be ported. The modify macros resemble closely quicklens, so as a prerequisite, I'm working (as we speak - though most of the work is done by @KacperFKorban) on porting quicklens to Scala 3 macros (https://github.com/softwaremill/quicklens/pull/66). That should also be a good learning experience so I'm hoping after implementing that, I'll be able to port tapir relatively quickly. But who knows what suprises lay ahead :)
I was wondering about using Magnolia vs Mirrors directly as well. Even though the layer is now much thinner, I think Magnolia still provides an more developer-friendly interface. So that's what I plan to use at least initially
Julien BENOIT
@jbenoit2011
Hi, in an streaming endpoint how to return an error response in 4xx or 5xx range when the returned stream is in error or empty ?
4 replies
Octav Zaharia
@octavz

hi, where I can find a simple example of a route that downloads a binary file?equivalent of this older code :

    endpoint.get
      .in("pdf")
      .out(header(HeaderNames.ContentType, "application/pdf"))
      .out(streamBody[Source[ByteString, Any]](schemaFor[Array[Byte]], CodecFormat.OctetStream()))
      .errorOut(errorHandler)

I need it to return the same type which is Endpoint[Request, ApiError, Source[ByteString, Any], Source[ByteString, Any]]

1 reply
Ahmet Turk
@ahmet_turk_gitlab
Hi all, I just had a hard time to setup simple tapir project due to the missing kind-projector. I see that -Ypartial-unification mentioned in both docs and readme but there was no indication that I needed kind-projector. Do you think kind-projector should be mentioned where it's applicable?
4 replies
PawelJ-PL
@PawelJ-PL
Hi, I've found two issues related to ZIO and prepared fixes. Could you take a look softwaremill/tapir#1195
6 replies
Nick Childers
@Voltir
Im looking to upgrade from sttp2 to sttp3 and there is an endpoint abstracted over its streaming type that im not sure how to write with the new capabilities model - eg, how would I take something like this: https://github.com/softwaremill/tapir/blob/master/examples/src/main/scala/sttp/tapir/examples/StreamingAkkaServer.scala but define the endpoint in such a way that its still a streaming endpoint, but not pinned to AkkaStreams ?
16 replies
Ender Tunc
@endertunc_gitlab
Hi, I just created a PR to add zio-json support. Please let me know if anything needs to be improved or fixed.
softwaremill/tapir#1197