Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Jan 24 14:06
    adamw commented #390
  • Jan 24 08:10
    erikvanoosten opened #390
  • Jan 23 13:37
    adamw closed #386
  • Jan 23 13:37
    adamw commented #386
  • Jan 23 13:36
    adamw commented #389
  • Jan 23 13:32

    softwaremill-ci on v0.12.17

    (compare)

  • Jan 23 13:32

    softwaremill-ci on master

    Setting version to 0.12.17 Setting version to 0.12.18-SNAP… (compare)

  • Jan 23 13:02

    adamw on master

    #386: Unset format for array ty… Merge pull request #389 from fr… (compare)

  • Jan 23 13:02
    adamw closed #389
  • Jan 23 10:14
    franklauterwald opened #389
  • Jan 23 06:45
    muej commented #383
  • Jan 22 17:09
    franklauterwald commented #386
  • Jan 22 14:57
    adamw commented #383
  • Jan 22 14:56
    adamw commented #384
  • Jan 22 14:55

    softwaremill-ci on v0.12.16

    (compare)

  • Jan 22 14:55

    softwaremill-ci on master

    Setting version to 0.12.16 Setting version to 0.12.17-SNAP… (compare)

  • Jan 22 13:21

    adamw on master

    Use non-deprecated api #383: add test (compare)

  • Jan 22 13:14

    adamw on master

    Fix example (compare)

  • Jan 22 13:12

    adamw on master

    add deprecated to info To supp… use plain Boolean in higher-lev… Merge pull request #384 from re… (compare)

  • Jan 22 13:12
    adamw closed #383
Patryk Celiński
@patrykcelinski
Am I interpreting this correctly that for None it will always return false?
Kasper Kondzielski
@ghostbuster91
@patrykcelinski AFAIK the easiest way is to include statusCode in error channel using .errorOut(statusCode) and then simply doing a pattern match
Patryk Celiński
@patrykcelinski
@ghostbuster91 I managed to solve my problem. I mapped Option to some other model and used statusMappingValueMatcher to match to the right status codes using on this model.
Jisoo Park
@guersam
Is there a simple way to get optional bearer token input EndpointInput[Option[String]] reusing existing tapir.auth.bearer?
mvillafuertem
@mvillafuertem

Hi, with the last version 0.12.12. I get this error

[error] /home/circleci/repo/applications/todo/src/main/scala/io/github/mvillafuertem/todo/api/ToDoAPI.scala:121:24: No TypeTag available for this.Out
[error]           statusMapping(
[error]

https://circleci.com/gh/mvillafuertem/scala/70

This work perfectly with 0.12.10

Thanks!

Kasper Kondzielski
@ghostbuster91
@mvillafuertem I took a peek at it but found nothing, could you please create an issue?
Kasper Kondzielski
@ghostbuster91
@guersam I am afraid that right now the easiest way is to copy httpAuth definition from tapir source code and to apply relevant modifications
Kasper Kondzielski
@ghostbuster91
@mvillafuertem As a workaround it seems that extracting statusMapping output as a value with explicit type fixes the issue
mvillafuertem
@mvillafuertem
@ghostbuster91 Thanks. I'm going to try it
Jisoo Park
@guersam
@ghostbuster91 Workarounded as you told and it just works, thanks!
Oswaldo Dantas
@oswaldo
Quick question (maybe). From the docs I had the impression there could be some way to generate tapir code from an existing swagger spec, but I don't seam to find any example about that or documentation clearly stating one way or another. So, is that something tapir is able to do or someone would need to extend swagger-codegen for that?
LukeDefeo
@LukeDefeo
hey guys just updated to 12.12 and cant seem to derive codecs via json any more, has something changed
import io.circe.generic.JsonCodec import sttp.tapir.json.circe._
 @JsonCodec
  case class Foo(a: String)


  def jsonCodecFoo: EndpointIO.Body[Foo, CodecFormat.Json, _] = {
    jsonBody[Foo]
      .description("producer schema")
      .example(Foo(""))
  }
Cannot find a codec for type: com.justeat.atticus.http.model.ResponseSchema.Foo, formatted as: sttp.tapir.CodecFormat.Json.
[error] Did you define a codec for: com.justeat.atticus.http.model.ResponseSchema.Foo?
[error] Did you import the codecs for: sttp.tapir.CodecFormat.Json?
[error] Is there an implicit schema for: com.justeat.atticus.http.model.ResponseSchema.Foo, and all of its components?
[error] (codecs are looked up as implicit values of type Codec[com.justeat.atticus.http.model.ResponseSchema.Foo, sttp.tapir.CodecFormat.Json, _];
[error] schemas are looked up as implicit values of type Schema[com.justeat.atticus.http.model.ResponseSchema.Foo])
[error] jsonBody[Foo]
any idea
vonchav
@voonchav_gitlab
I think you might need to define a Validator in scope. I hit this problem a few weeks ago. I've been meaning to open an issue for that, because 1) in v0.11.x, Validator wasn't needed for some reason; 2) Adam asked me so I suppose he might think it could be legit too.... I have some good examples to showcase both v0.11 and v0.12. I just need to sit down to cross-check and clean up a bit. Then I will open an issue. In the meantime, try simply adding the following and see if this error goes away: implicit val _: Valiator[Foo] = Validator.pass[Foo]
Carlos Martin
@butcherless

Hello everyone,

I just updated tapir from 0.12.12 to 0.12.13 and I get a runtime error with the same source code (no changes) that was working. I'm using uPickle to encode/decode JSON objects and the case class 'Book' of the documentation examples https://tapir-scala.readthedocs.io/en/latest/endpoint/json.html

java.util.NoSuchElementException: key not found: SObjectInfo(com.cmartin.learn.web.ApiModel.Book,List())

Do you have any idea what may be happening? Thanks!!!

Here's part of the stacktrace of the RuntimeException:

2020-01-09 11:04:42,103 ERROR [WebActorSystem-akka.actor.default-dispatcher-5] akka.actor.ActorSystemImpl              :? - Error during processing of request: 'key not found: SObjectInfo(com.cmartin.learn.web.ApiModel.Book,List())'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
java.util.NoSuchElementException: key not found: SObjectInfo(com.cmartin.learn.web.ApiModel.Book,List())
    at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:226)
    at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:222)
    at sttp.tapir.docs.openapi.schema.SchemaReferenceMapper.map(SchemaReferenceMapper.scala:8)
    at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:19)
    at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:13)
    at sttp.tapir.docs.openapi.CodecToMediaType.apply(CodecToMediaType.scala:13)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse$$anonfun$2.applyOrElse(EndpointToOperationResponse.scala:77)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse$$anonfun$2.applyOrElse(EndpointToOperationResponse.scala:76)
    at scala.collection.StrictOptimizedIterableOps.collect(StrictOptimizedIterableOps.scala:151)
    at scala.collection.StrictOptimizedIterableOps.collect$(StrictOptimizedIterableOps.scala:136)
    at scala.collection.immutable.Vector.collect(Vector.scala:119)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse.outputsToResponse(EndpointToOperationResponse.scala:76)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse.$anonfun$outputToResponses$1(EndpointToOperationResponse.scala:26)
    at scala.collection.StrictOptimizedMapOps.flatMap(StrictOptimizedMapOps.scala:33)
    at scala.collection.StrictOptimizedMapOps.flatMap$(StrictOptimizedMapOps.scala:32)
    at scala.collection.immutable.ListMap.flatMap(ListMap.scala:42)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse.outputToResponses(EndpointToOperationResponse.scala:23)
    at sttp.tapir.docs.openapi.EndpointToOperationResponse.apply(EndpointToOperationResponse.scala:14)
    at sttp.tapir.docs.openapi.EndpointToOpenApiPaths.endpointToOperation(EndpointToOpenApiPaths.scala:47)
    at sttp.tapir.docs.openapi.EndpointToOpenApiPaths.pathItem(EndpointToOpenApiPaths.scala:25)
    at sttp.tapir.docs.openapi.EndpointToOpenAPIDocs$.$anonfun$toOpenAPI$2(EndpointToOpenAPIDocs.scala:19)
    at scala.collection.immutable.List.map(List.scala:219)
    at scala.collection.immutable.List.map(List.scala:79)
    at sttp.tapir.docs.openapi.EndpointToOpenAPIDocs$.toOpenAPI(EndpointToOpenAPIDocs.scala:19)
    at sttp.tapir.docs.openapi.TapirOpenAPIDocs$RichOpenAPIEndpoints.toOpenAPI(TapirOpenAPIDocs.scala:19)
    at sttp.tapir.docs.openapi.TapirOpenAPIDocs$RichOpenAPIEndpoints.toOpenAPI(TapirOpenAPIDocs.scala:16)
    at com.cmartin.learn.web.SwaggerApi.openApi(SwaggerApi.scala:13)
    at com.cmartin.learn.web.SwaggerApi.openApi$(SwaggerApi.scala:11)
    at com.cmartin.learn.web.SwaggerApi$.openApi$lzycompute(SwaggerApi.scala:32)
    at com.cmartin.learn.web.SwaggerApi$.openApi(SwaggerApi.scala:32)
    at com.cmartin.learn.web.SwaggerApi.$anonfun$route$5(SwaggerApi.scala:25)
    at akka.http.scaladsl.server.directives.RouteDirectives.$anonfun$complete$1(RouteDirectives.scala:47)
    at akka.http.scaladsl.server.StandardRoute$$anon$1.apply(StandardRoute.scala:19)
    at akka.http.scaladsl.server.StandardRoute$$anon$1.apply(StandardRoute.scala:19)
Carlos Martin
@butcherless

Hello again,

I get the same error this time with Circe encoder/decoder in a Service that was working with Tapir version 0.12.12. No code changes. Thanks.

asset-composer-service 2020-01-09 11:23:19,151 ERROR [AssetComposerServiceApplicationLocal-akka.actor.default-dispatcher-5] akka.actor.ActorSystemImpl              :? - Error during processing of request: 'key not found: SObjectInfo(io.circe.Json,List())'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
asset-composer-service java.util.NoSuchElementException: key not found: SObjectInfo(io.circe.Json,List())

More detailed stacktrace below:

asset-composer-service   Request : HttpRequest(HttpMethod(GET),http://localhost:8080/api/v1.0/docs/docs.yaml,List(Timeout-Access: <function1>, Host: localhost:8080, Connection: keep-alive, Accept: application/json, */*, User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36, Sec-Fetch-Site: same-origin, Sec-Fetch-Mode: cors, Referer: http://localhost:8080/api/v1.0/docs/index.html?url=/api/v1.0/docs/docs.yaml, Accept-Encoding: gzip, deflate, br, Accept-Language: en-US, en;q=0.9, es-ES;q=0.8, es;q=0.7),HttpEntity.Strict(none/none,0 bytes total),HttpProtocol(HTTP/1.1))
asset-composer-service   Response: Rejected(List())
asset-composer-service 2020-01-09 11:23:19,151 ERROR [AssetComposerServiceApplicationLocal-akka.actor.default-dispatcher-5] akka.actor.ActorSystemImpl              :? - Error during processing of request: 'key not found: SObjectInfo(io.circe.Json,List())'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
asset-composer-service java.util.NoSuchElementException: key not found: SObjectInfo(io.circe.Json,List())
asset-composer-service     at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:226)
asset-composer-service     at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:222)
asset-composer-service     at sttp.tapir.docs.openapi.schema.SchemaReferenceMapper.map(SchemaReferenceMapper.scala:8)
asset-composer-service     at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:19)
asset-composer-service     at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:13)
asset-composer-service     at sttp.tapir.docs.openapi.CodecToMediaType.apply(CodecToMediaType.scala:13)
asset-composer-service     at sttp.tapir.docs.openapi.EndpointToOperationResponse$$anonfun$2.applyOrElse(EndpointToOperationResponse.scala:77)
asset-composer-service     at sttp.tapir.docs.openapi.EndpointToOperationResponse$$anonfun$2.applyOrElse(EndpointToOperationResponse.scala:76)
asset-composer-service     at scala.collection.StrictOptimizedIterableOps.collect(StrictOptimizedIterableOps.scala:151)
asset-composer-service     at scala.collection.StrictOptimizedIterableOps.collect$(StrictOptimizedIterableOps.scala:136)
asset-composer-service     at scala.collection.immutable.Vector.collect(Vector.scala:119)
asset-composer-service     at sttp.tapir.docs.openapi.EndpointToOperationResponse.outputsToResponse(EndpointToOperationResponse.scala:76)
asset-composer-service     at sttp.tapir.docs.openapi.EndpointToOperationResponse.$anonfun$outputToResponses$1(EndpointToOperationResponse.scala:26)
vonchav
@voonchav_gitlab
I upgraded to 0.12.13 and I'm using Circe. All my unit tests and int tests are passing. But I haven't found the time to test E2E so fingers crossed.
Kasper Kondzielski
@ghostbuster91
@butcherless can you try 0.12.13 ?
mvillafuertem
@mvillafuertem

Hello,

I get the same error that @butcherless before update to 0.12.13.

Exception in thread "main" java.util.NoSuchElementException: key not found: SObjectInfo(io.circe.Json,List())
    at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:226)
    at scala.collection.immutable.Map$EmptyMap$.apply(Map.scala:222)
    at sttp.tapir.docs.openapi.schema.SchemaReferenceMapper.map(SchemaReferenceMapper.scala:8)
    at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:19)
    at sttp.tapir.docs.openapi.schema.ObjectSchemas.apply(ObjectSchemas.scala:13)

With 0.12.12 this work

I have created a minimal project to check this issue

https://github.com/mvillafuertem/tapir-schema-error

Thanks!

rabzu
@rabzu
Is there a way to test routes in tapir without starting up server and client: by just calling function?
Kasper Kondzielski
@ghostbuster91
@rabzu I think that currently it depends on the interpreter you use. If you use http4s you just need to convert your tapir endpoints to http4s.routes and then you have function from Request to Response
rabzu
@rabzu
thank you
Gergő Törcsvári
@tg44
Hy! I try to convert my akkahttp endpoint to tapir (this is the first so probably the main reason I really stragleing :D ) Is there any reason why we don't have a def serverLogic[F[_]](f: I => EitherT[Future,E, O]]): ServerEndpoint[I, E, O, S, F] = ServerEndpoint(this, f.value) ?
(I know I can write an implicit converter, but still, for every simple Future[A] I need to wrap them to a Future[Right[A]]... plus keeping the future as a monaderror, which contains an another monaderror is a bit to much for my taste :D )
Paweł Gontarz
@Garnek20

Hello! I'm looking for a way to decode two query params into a single case class (mostly because I want to provide validation logic to the composed type). Is it doable with tapir?
What I'm seeing is that there is a codec attached to Query type, but this one, from my understanding, can be only associated with one query param.

Thanks :)

Kasper Kondzielski
@ghostbuster91
@Garnek20 maybe sth like that : endpoint.in(query("q1").and(query("q2")).mapTo(MyCaseClass)) ? And you can have validation logic inside MyCaseClass constructor
Paweł Gontarz
@Garnek20
@ghostbuster91 thanks for getting back so fast. Indeed that seems like a solution. Do you know from where implicit implicit fc: FnComponents[COMPANION, I, CASE_CLASS] required for .mapTo come from?
Kasper Kondzielski
@ghostbuster91
They come from tapir, you should not worry about them ;)
Paweł Gontarz
@Garnek20
@ghostbuster91 the problem with that is though that if validation fails, how can I reject the request - similarly to akka's rejection?
Kasper Kondzielski
@ghostbuster91
Although I am sure that it is possible maybe the simpler approach would be to move the validation from case class constructor to Validator[MyCaseClass]. If you specify validator as implicit it should be taken into account.
Kasper Kondzielski
@ghostbuster91
So, actually the easiest way right now might be to do it outside tapir. Accept queries and in your endpoint logic perform validation, in case of failure return bad request or whatever you want
val myEndpoint  = endpoint.in(query[String]("q1"))
.errorOut(statusCode)
.out(jsonBody[Response])
.serverLogic{ case q1=> 
     someCustomValidation(q1).fold(error => Left(BadReqest), ok => Response())
}
more or less like above ;)
Paweł Gontarz
@Garnek20
@ghostbuster91 I see :) thanks !
Would it make sense to have a QueryMany type that is with big simplification something like:
case class QueryMany(queries: Seq[Query]) ... ? Then I think composed validation would be possible. If you find that it indeed might be nice to have, I could try to work on PR :)
Kasper Kondzielski
@ghostbuster91
I think that a more likely solution would be to add a validator to endpointInput but if you create an issue we would be able to discuss it there in more details
Adam Warski
@adamw
@Garnek20 I'd say that validation should be only attached to single inputs/outputs. Then we can translate it to documentation. Anything more sophisticated (taking into account multiple inputs or contextual) should go into the server logic
Jacob Wang
@jatcwang

I'm currently using tapir and interpreting clients from it. I'm using .toSttpRequest in order to handle unexpected server breaking changes. However, I'm not able to access the original body anymore. Has anyone else had this problem?

(I understand that we have streamed body so it's not guaranteed that things are fully in memory. I'm wondering whether there's a way to keep the body around when you need it the most..)

Jacob Wang
@jatcwang
@adamw if this makes sense:
val myTapirEndpoint: Endpoint[UserId, MyError, MyBody, Nothing] = ...

val response: Response[DecodeResult[Either[MyError, MyBody]]] = myTapirEndpoint.toSttpRequest.apply(userId).send()

response.body match {
  case e: DecodeFailure => // Critical failure, log status code and raw response body
  case DecodeResult.Value(Left(e)) => // handle expected business logic error here
  case DecodeResult.Value(Right(r)) =>  // handle success
}
One way to solve it would be to add the raw body to tapir.model.Response (if it wasn't a stream body). There are most likely better ways, ofc
vonchav
@voonchav_gitlab
In my Tapir project (a CRUD api), I wrote an sttp interpreter by calling toSttpRequest. It serves two purposes: 1) I use this client to do integration tests 2) use this client as the JS client in my ScalaJs frontend app (via the Fetch backend). Thereby this sttp interpreter needs to be cross-compiled to jvm & js. Since the interpreter is derived from my tapir endpoints, doesn't it mean my tapir endpoint definitions also needs to be cross-compiled to JS too? I looked at Tapir project . It doesn't appear to be configured as a cross-project . How should I go about it to achieve my goal? I try to avoid re-creating sttp client without reusing my tapir definitions.
Jacob Wang
@jatcwang
@voonchav_gitlab softwaremill/tapir#98
Anton Solovyev
@Rosteelton
Hi all! What the best way to log the response body with tapir (akka-http interpreter)?
Anton Solovyev
@Rosteelton
and request body with query params
AC
@ACJustPlay
Hello!
I'm using tapir "0.12.15" , scala "2.13.1", http4s "0.21.0-RC1" and getting a NoSuchMethodError with SwaggerHttp4s
java.lang.NoSuchMethodError: org.http4s.StaticFile$.fromResource(Ljava/lang/String;Lscala/concurrent/ExecutionContext;Lscala/Option;ZLcats/effect/Sync;Lcats/effect/ContextShift;)Lcats/data/OptionT;
        at sttp.tapir.swagger.http4s.SwaggerHttp4s$$anonfun$routes$1.applyOrElse(SwaggerHttp4s.scala:56)
        at sttp.tapir.swagger.http4s.SwaggerHttp4s$$anonfun$routes$1.applyOrElse(SwaggerHttp4s.scala:44)
        at scala.PartialFunction$Lifted.apply(PartialFunction.scala:310)
        at scala.PartialFunction$Lifted.apply(PartialFunction.scala:306)
        at org.http4s.HttpRoutes$.$anonfun$of$2(HttpRoutes.scala:63)
        at cats.effect.internals.IORunLoop$.liftedTree1$1(IORunLoop.scala:95)
        at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:95)
        at cats.effect.internals.IORunLoop$RestartCallback.signal(IORunLoop.scala:355)
        at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:376)
        at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:316)
        at cats.effect.internals.IOShift$Tick.run(IOShift.scala:36)
        at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
        at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
did I miss anything or should I change the library versions?
Henry
@hygt
Hello! Is there a way to customize multiple value query parameters (type, explode)?
I see the ParameterStyle enum in sttp.tapir.openapi but I cannot figure out how to use that when I define my endpoint