Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 15 17:57
    tomasherman commented #1526
  • Oct 15 17:54
    tomasherman synchronize #1526
  • Oct 15 17:47
    tomasherman commented #1526
  • Oct 15 17:42
    tomasherman synchronize #1526
  • Oct 15 14:23

    mergify[bot] on master

    Update akka-stream to 2.6.17 Merge pull request #1536 from s… (compare)

  • Oct 15 14:23
    mergify[bot] closed #1536
  • Oct 15 13:23
    mergify[bot] labeled #1536
  • Oct 15 13:22
    scala-steward opened #1536
  • Oct 15 11:54
    bartekzylinski assigned #1434
  • Oct 15 11:43

    mergify[bot] on head-range-support

    (compare)

  • Oct 15 11:43

    adamw on master

    Implemented accept range support Added test Added handling of HEAD requests… and 16 more (compare)

  • Oct 15 11:43
    adamw closed #1527
  • Oct 15 11:23
    bartekzylinski synchronize #1527
  • Oct 15 11:23

    bartekzylinski on head-range-support

    Fixed setup of double endpoints… (compare)

  • Oct 15 10:48
    adamw commented #1203
  • Oct 15 09:35
    xeppaka commented #1203
  • Oct 15 09:09
    micossow synchronize #1508
  • Oct 15 06:49
    xeppaka commented #1203
  • Oct 14 22:20

    mergify[bot] on master

    Update swagger-ui to 3.52.5 Merge pull request #1535 from s… (compare)

  • Oct 14 22:20
    mergify[bot] closed #1535
Nicholas Molenaar
@nmolenaar
And:
 could not find implicit value for evidence parameter of type sttp.tapir.Schema[
While I did extend my class with the trait TapirJsonCirce
Nicholas Molenaar
@nmolenaar
It has something todo with the Joda DateTime fields I got.
Nicholas Molenaar
@nmolenaar

Nope, fixed the issue with the Joda datetime, im still stuck on

could not find implicit value for evidence parameter of type sttp.tapir.Schema[com.molenaar.module.content.http.ContentHttpDomain.ContentHttpSingleResponse]

Any one got an idea for this matter?

5 replies
Thijs Broersen
@ThijsBroersen
How can I create an endpoint with multiple response content-types? I noticed content negotiation is not yet implemented (softwaremill/tapir#248) but is it possible to (at least) create OpenAPI yaml which contains all possible content-types? Currently I am only able to have it displayed a single Content-Type.
Alexander Korablev
@kor85
Hi! I'm trying to use http4s middleware with tapir and i'm stuck with middleware which modify request/response types. I don't understand how i can model this routes with tapir endpoints?
The problem is that Endpount.toRoutes return HttpRoutes when i want AuthService.
balthz
@balthz
Hey folks, first of all, Tapir is a pleasure to use, thanks for it! One very high-level question I have is whether there's a way to combine two Endpoints and then interpret them (to a server, say). Or is the idea to interpret Endpoints separately and combine them using the capabilities of the target HTTP library? If so, why is that?
1 reply
Clint Combs
@ClintCombs
I see the first tapir commit was September 21, 2018, but the main README says "Tapir is an early stage project." Is that still true? How stable are the APIs? Are there any major changes planned in the near future?
2 replies
Andy Czerwonka
@andyczerwonka
Just wondering if anyone has encountered softwaremill/tapir#887
Blaž Marinović
@bmarinovic

hi :) I want fine-grained errors, meaning for all endpoints I'd use errorBaseEndpoint (like in documentation https://tapir.softwaremill.com/en/latest/endpoint/statuscodes.html) and just for some endpoints also add BadRequest. Is it possible to "flatten"/untuple the errors , because when I try:

BaseEndpoints.errorBaseEndpoint
      .prependErrorOut(
        oneOf[ErrorInfo](
          statusMapping(StatusCode.BadRequest, jsonBody[ErrorInfo.BadRequest].description("bad request"))
        )
      )

My error type is (ErrorInfo, ErrorInfo)

1 reply
Thai Dang Vu
@dxxvi

Hi All, I'd like to declare a post endpoint which takes a bunch of people case class Person(id: Long, name: String) without id's, i.e. the request body is like

[ { "name": "a" }, { "name": "b" } ]

The response will be those people with id's generated on the server with status code of 201 (CREATED). My endpoint is

val postPeopleEndpoint: Endpoint[String, ErrorInfo, Iterable[Person], Any] = endpoint
        .post
        .in("people")
        .in(stringBody) // this is string, not jsonBody[Iterable[Person]]
        .errorOut(oneOf[ErrorInfo](
            statusMapping(StatusCode.BadRequest, jsonBody[BadRequest])
        ))
        .out(jsonBody[Iterable[Person]])

That endpoint will return a status code of 200. How can I make it return 201?

Gerard Madorell
@GMadorell
Hey @dxxvi, you can use
.out(statusCode(StatusCode.Created))
On the endpoint

Btw, I have an example of an authenticated endpoint blueprint (an endpoint that is a PartialServerEndpoint, with the authentication logic built in around an optional bearer input).

That same endpoint is then extended by each final endpoint, which implements the custom logic.
The problem I'm facing is that those final endpoints also have inputs (body inputs to be exact, parsing json).
So I cannot make a test that fails with a 401, because the body input makes the route fail before, with a 400 error, when no body is in the request.

Is there an option to make it fail with a 401 when no body is there?

1 reply
Thai Dang Vu
@dxxvi

@GMadorell Thank you very much for your help.

So I cannot make a test that fails with a 401
I think one issue with this declarative way is that it's not flexible. I dealt with your issue with .in(stringBody).errorOut(oneOf ... and let the server logic return a particular Left[ParticularType] which is mapped to a particular http status code.
I wish that the Tapir had more examples in github.

Andy Czerwonka
@andyczerwonka

@adamw I have a strange issue where I modify a schema to add a description, and for one field it works, and for the other is does not.

  implicit val responseSchema: Schema[DesignExecutionResponse] =
    implicitly[Derived[Schema[DesignExecutionResponse]]].value
      .modify(_.score)(_.description("The score that was used to generate candidates"))
      .modify(_.descriptors)( _.description("The descriptors that correspond to all the variable keys in the design results"))

The second description is generated, but the first is not. Any thought on where I would look to debug that?

1 reply
mvillafuertem
@mvillafuertem
Hi all, How can I add a timeout request? It is posible?
mvillafuertem
@mvillafuertem
This is my current code. I would like to add this http response to Tapir's endpoint. it's possible?

val routes: Route = withRequestTimeoutResponse(request =>
            HttpResponse(StatusCodes.EnhanceYourCalm, entity = "Unable to serve response within time limit, please enhance your calm.")
          ) {
loginUser.toRoute { _ =>
              Future(Right(logic))
            }
}
2 replies
Daniel Robert
@drobert

I think I'm missing a simple example of server logic error handling. I have F[MyType] as my effect (closely following https://tapir.softwaremill.com/en/latest/server/logic.html#recovering-errors-from-failed-effects ). endpoint shape is endpoint.in("somePath").out(jsonBody[MyType])

At this point, the type is ServerEndpoint[Unit, Unit, MyType, Any, F]. I'm trying to produce a ServerEndpoint that returns no body on error, but returns an appropriate status code on error. I was thinking serverLogic(_ => existingLogic) where existingLogic returns F[MyType].

Using serverLogic with attempt has a type issue as the endpoint thus far delares error type to be Unit (expects F[Either[Unit, MyType]]. Using serverLogicRecoverErrorssimilarly already expects E <:< Throwable but E has only been built up to be Unit so far.

Is there a simple way of doing this?

Daniel Robert
@drobert
(for context, I have an existing http4s set of routes I'm looking to convert to tapir for the sake of automatic openapi documentation, etc.)
Daniel Robert
@drobert
possibly I'm confused because Tapir seems to require me to handle the error but the http4s service it'll be generating has some error handling built in
Daniel Robert
@drobert

perhaps more specifically: documentation in Exception Handling states:

If the logic function, which is passed to the server interpreter, fails (i.e. throws an exception, which results in a failed Future or IO/Task), this is propagated to the library (akka-http or http4s).

But I fail to see how it gets propagated; seems like the errorOut declaration (to coerce the error type to Throwable) would result in this being caught/handled by tapir. At the last, it shows up in OpenAPI documentation with whatever status code mapping is applied to Throwable

6 replies
vonchav
@voonchav_gitlab
Hi @adamw, if you can update the sttp deps (sttp-client, sttp-model, sttp-shared) to the latest versions in https://github.com/softwaremill/tapir/blob/master/project/Versions.scala, that'd be the great. In the meantime, I'm updating a couple of breaking changes in tapir 0.17.1 (namely toRoutes and toOpenAPI). Looking forward to more tapir/sttp awesomeness :)
5 replies
Daniel Robert
@drobert
I have a case class that I also have circe codecs defined for. I've added @description("blah") to the case class. Using automatic derivation, I do not see this description in the resulting doc. But using implicitly[Derived[Schema[MyType]].value.description("but this works") I do see such a thing.
Is this expected behavior?
6 replies
Daniel Robert
@drobert
seems to work as expected with semi-auto derivation (but not fully auto derivation)
Adam Warski
@adamw

Thank you for being part of the tapir community - Merry Christmas & a more regular 2021 ;)

who knows, maybe we'll manage to bring tapir to 1.0 in the next year? :)

strobe
@strobe

Hi, I'm digging around AsyncAPI docs generation, got success with some initial stuff,
but not sure how to customize documentation of in/out messages.

For example:

case class Response(hello: String)

val wsEndpoint: Endpoint[Unit, Unit, Flow[String, Response, Any], AkkaStreams with WebSockets] =
  endpoint.get.in("ping").out(webSocketBody[String, CodecFormat.TextPlain, Response, CodecFormat.Json](AkkaStreams))

How to specify the 'description' tag of 'Response' here?

2 replies
kazchimo
@kazchimo
Hi.
Is there way to use ziostream endopint with http4s server?
Examples show only Akkastrems with akka-http or http4s + fs2 streaming.
And it looks like http4s has no capabilities with ziostreams.
if so what is the best practice of using Ziostream as endpoint with tapir?
Thanks.
Jens Grassel
@jan0sch
FYI: I updated the gitter8 template for the http4s-tapir service to work with 0.17. Just create it as usual via sbt new https://codeberg.org/wegtam/http4s-tapir.g8.git and you're ready to go.
Daniel Robert
@drobert
I'm finding an awkward data model in my code base that's effectively Array[Tuple2[TypeA, TypeB]] and I can't find any auto- or semiauto-derived way of generating a valid schema.
On the Json side, this is ultmately [ [ { /* type a */ }, { /* type b */ } ], [ ... ] ]. I'm not entirely sure if this is supported by openapi but if so, could tapir generate such a data type?
4 replies
Anders Schwartz
@adschwartz

Hi! I am using tapir to create a post endpoint (with http4s as backend) that can receive a file (as byte array) through multipart submission and I am looking to add a filter/check that would stop submitters from uploading files over a certain size, e.g. 100MB (this is mainly to protect the server from malicious use). What would be the idiomatic way to implement such a check using tapir? I am looking to fail the upload if the uploaded content exceeds the limit (and not wait until the full upload has completed).

I've considered a couple of options but none seem great:

  • check the content-length header (but it could be missing or inaccurate and I only seem to be able to evaluate it after the data has been received by http4s)
  • check the File size after uploaded (again too late)
  • somehow process the stream as it's coming in and reject immediately if the accumulated upload exceeds. I haven't been able to track down any resources/docs/examples on this option.
  • set max chunk size (but that would still not prohibit the full upload to exceed the limit)
  • using a stream as an input and somehow keeping a tally of the accumulated input and failing fast
1 reply
Daniel Robert
@drobert
Codec.mapDecode - if I'm reading this correctly, it will always reset the validator to Validator.pass.
It delegates to map(Mapping.fromDecode(...)) which:
  • Mapping.fromDecode hard-codes Validator.pass
  • map(codec: Mapping[H, HH]]) calls outer.schema.contramap(codec.encode).validate(codec.validator) which will replace the Schemas validator with the new always pass version, won't it?
Daniel Robert
@drobert
is it intentional that emptyOutput does not allow for a .description?
Evgenii Kuznetcov
@simpadjo

Hello folks!
First, thank you for the awesome library!

I'm trying learn enough of it to protect myself against Spring Boot at work.

Spring allows to generate typed http clients in a single step:
Something like (Api, Url) => ClientApiImpl. This is what people usually want: just an object with (I => Future[O]) method and all http stuff being encapsulated.

As far as I could find, Tapir requires to do some plumbing to achieve that.
1) create an http interpreter val cl = SttpClientInterpreter.toRequestUnsafe(apiDef, url)
2) create a backend val backend = HttpURLConnectionBackend()
3) Manually declare an http-free interface, write boilerplate implementation like i => backend.send(cl(i))

Is there an interpreter that takes an api, url, backend (optional?) and does it for me? That would be much more easy to sell.

Evgenii Kuznetcov
@simpadjo
Just understood that it's achievable with a helper function:
 def mkSimpleClient[I, E, O](api: ZEndpoint[I, E, O], uri: String): (I => Either[E, O]) = {
    val backend = HttpURLConnectionBackend()
    val fn = SttpClientInterpreter
      .toRequestUnsafe(api, Uri(uri))

    i: I => {
      backend.send(fn(i)).body
    }
  }
Evgenii Kuznetcov
@simpadjo
I made a PR about this topic: softwaremill/tapir#920
vonchav
@voonchav_gitlab

@adamw , just an FYI, I think currently sttp-client 3.0.0-RC14 doesn't work with tapir 0.17.1, because sttp-client 3.0.0-RC14 uses sttp-model 1.2.0-RC12, which has changes that are not binary compatible with the version that tapir 0.17.1 uses. I get module-not-found error when using them together. No big deal as I'm sure you're aware of that and you're in the middle of preparing a Tapir release :)

Another thing I noticed is that sttp-shared 1.0.0-RC12 is still using sttp-model 1.2.0-RC11. With the aforementioned compatibility issue, it'd like to sync all of them :)

I've kind of figured out the dependency relationship of these modules:
tapir <depends on> sttp-client <depends on> sttp-shared <depends on> sttp-model
haha. Thanks.

4 replies
vonchav
@voonchav_gitlab

Hi Adam and all, my question is in regards to setting headers in HTTP response:

If I want to return headers such as X-Frame-Options and X-XSS-Protection with static/fixed values, what is the best way to add them in Tapir endpoints?

The standard approach is to build off the base Endpoint, add .out( header[A]("foo") ) then, before returning in .serverLogic, I add the values to complete the tuple. For example, if my server logic returns a Long and the values of both my http headers are strings, my tuple would be (Long, String, String).

With this approach, I have to repeat this for all my endpoints.

I can use either serverLogicForCurrent or serverLogicPart. With serverLogicForCurrent, I'd add/resolve the header values in my base endpoints. However, that will pass down these values down to serverLogic and I will have to compose the final tuple at the end of serverLogic.

I haven't used serverLogicPart. From the docs, it seems that, once the values are added into the headers, the endpoint is "considered complete, and cannot be later extended", as I'm quoting from the docs. This isn't what I'm looking for. What I'm looking for is a hybrid of serverLogicForCurrent and serverLogicPart: I'd like to resolve the header values ahead of serverLogic and then allow this base implementation be to further composed without the need of passing down these header values (because they are already resolved) as well as the re-assembly at the end.

I might be overthinking this or I might misunderstand the docs. Please correct me if that's the case.

All these sound a bit complicated, haha. That's kind of my point. Basically I'm looking for an elegant/idiomatic way in Tapir that allows me to build a base endpoint with fixed headers (with static values). Other endpoints can then be derived from this base implementation and all these endpoints will return the same headers in response.

Any suggestions are welcome. Thank you.

6 replies
Denis Novac
@DenisNovac
Hi everyone. I guess, there is an error in migration guide to 0.17 (on release page). It says "instead stream types, e.g. Endpoint[I, E, O, Source[ByteString, Any]], use the capability: Endpoint[I, E, O, Source[ByteString, Any]]" but it is the same code written twice. What should i do to migrate? It seems that Endpoint[I, E, O, Fs2Streams[F]] does not work.
Denis Novac
@DenisNovac
The Endpoint[I, E, O, Fs2Streams[F]] change actually works
1 reply
Denis Novac
@DenisNovac

Is it possible to create schema for Map type?

This code says there is no implicit Schema:

val endpoint
      : Endpoint[Unit, (StatusCode, EndpointError), Map[MyIdClass, List[Description]], Any] =
    baseEndpoint.get
      .in("test")
      .out(jsonBody[Map[MyIdClass, List[Description]]])

Every custom type has Schema in companion. For example, this type works good:

List[(MyIdClass, List[Description])]
1 reply
Vladimir Bodnartchouk
@Fraer
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
@DenisNovac

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)?

https://scastie.scala-lang.org/XtuqptggQ36yJ9Dt4gSuvA

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
@DenisNovac

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
mvillafuertem
@mvillafuertem

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
@DenisNovac
Hi everyone. Getting this error while migrating to 0.17:
java.lang.ExceptionInInitializerError:
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
@DenisNovac
Actually MyType does not even have a schema, it is only for internal usage.
Denis Novac
@DenisNovac

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
jjcapper
@jjcapper
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