Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 16:26
    adamw closed #510
  • 16:26
    adamw commented #510
  • 16:24
    adamw opened #1665
  • 16:24

    adamw on log-without-monaderror

    Remove the requirement in Defau… (compare)

  • 16:04
    adamw reopened #1658
  • 16:04
    adamw commented #1658
  • 14:31
    soujiro32167 closed #1658
  • 14:31
    soujiro32167 commented #1658
  • 11:30
    hochgi edited #1663
  • 10:12
    mergify[bot] labeled #1664
  • 10:11
    scala-steward opened #1664
  • 08:31
    adamw commented #1662
  • 08:31

    adamw on master

    Added ability to map error type… Merge pull request #1662 from s… (compare)

  • 08:31
    adamw closed #1662
  • 08:31
    adamw closed #1660
  • 08:19

    adamw on master

    Rename parameters Merge pull request #1661 from e… (compare)

  • 08:19
    adamw closed #1661
  • 08:19

    mergify[bot] on attributes

    (compare)

  • 08:19
    adamw commented #1661
  • 08:19

    mergify[bot] on multipart-v2

    (compare)

dharm82465
@dharm82465
.out(
        oneOf[AkkaStreams.BinaryStream](
          oneOfMappingValueMatcher(Ok, EndpointIO.StreamBodyWrapper(streamTextBody(AkkaStreams)(CodecFormat.Json()))){
            case _: AkkaStreams.BinaryStream => true
          },
          oneOfMappingValueMatcher(Ok, EndpointIO.StreamBodyWrapper(streamTextBody(AkkaStreams)(CodecFormat.TextPlain()))){
            case _: AkkaStreams.BinaryStream => true
          }
        )
      )
Gerry Fletcher
@gerryfletch

Is it possible to type the Input tuple as a case class? When there are many variables of the same type, it would be nice to have them named. Here's the one I'm interested in:

  def postContent[F[_]: Applicative]: PartialServerEndpoint[
    String,
    User,
    (UUID, UUID, String, ContentForm),

Would be nice to use a case class to name the UUIDs

2 replies
Gabriel Asman
@Qthunder

Hello

I tried upgrading a project from 0.17.20 --> 0.18.3 and am hitting a bug(?)

Basically I have something like this for my endpoints

  val getThing: Endpoint[String, Unit, Thing, Any] =
    endpoint.get
      .in(path[String]("id"))
      .out(jsonBody[Thing])

  val getThings: Endpoint[NonEmptyList[Filter], Unit, List[Thing], Any] =
    endpoint.get
      .in(query[NonEmptyList[Filter]]("filters"))
      .out(jsonBody[List[Thing]])

Similar endpoints, but one has a path parameter (id) and the other has a query parameter (filters). This worked just fine before, but with the upgrade it seems like tapir (using the http4s interpreter) cannot adequately discriminate between the two when matching a request. Basically all requests - regardless of path or query parameters - will be matched by both endpoints (in practice whichever came first in the combined routes). The problem is just with these kind of endpoints if I change getThing path to something like .in("id" / path[String]("id")), there's no issue.

For what is worth, this is the code I use to combine

def combinedRoutes: HttpRoutes[IO] =
    List(getThing, getThings)
      .foldMapK(Http4sServerInterpreter().toRoutes(_))

I've scanned the changelogs the best I could to try and guess what might be causing this. I am aware this may very well be about the http4s version bump rather than tapir - nonetheless any help would be appreciated :)

18 replies
counter2015
@counter2015
Hi, I'm using tapir-redoc 0.19.0-M14 to generate document, It seems the redoc can't make the call request directly from the browser like swagger, is there any good idea?
3 replies
whatsmore, the generate doc has a long title for each api.
for example, GET /v1/{somthing}/{anything}/id/{id} will generage a title getV1SomthingAnythingIdId, can I modify it ?
3 replies
lbirnicu
@lbirnicu:matrix.org
[m]
Hello everyone!
I would like to upgrade my project to cats 3, which means I will have to upgrade to a tapir version beyond v0.18.3. I am not sure what does the M in the versioning stand for (if it is milestone), but my question is - would it be safe to upgrade to tapir v0.19.0-M11 let's say ? Please let me know - thank you !
4 replies
lbirnicu
@lbirnicu:matrix.org
[m]
Thanks for the reply Adam!
Grant
@gavares

I’ve updated to the latest M14 release and so far I really the addition of securityIn. One thing I’m struggling with is how I might combine the U and I parameters in a ZPartialServerEndpoint. I have a base request type that contains common headers I expect to be on all requests. This type is returned from my base endpoint like:

val baseEndpoint: Endpoint[Unit, BaseRequest, MyError, Unit, Any] = ///

I then extend this base endpoint for secured endpoints like this:

val secureEndpoint: ZPartialServerEndpoint[Has[AuthNService], List[Header], User, BaseRequest, MyError, Unit, Any] =
    baseEndpoint.securityIn(authHeadersInput).zServerSecurityLogic(AuthNService.authN)

Endpoints derived from secureEndpoint now have a severLogic component with a signature like:

(user: User => ((baseReq: BaseRequest, req: EndpointRequest)) => ….)

which is a bit awkward. Ideally, I’d like to map over these parameters before they are passed to my serverLogic function so that serverLogic signature looks more like:

(authdReq => …)

where the authdReq param is a case class that combines the user, some fields from the BaseRequest, and the inputs for the endpoint in question.

4 replies
Grant
@gavares
A concreate example would be ensuring that every inbound request has a request id attached to is and ensuring every response includes that same request id as a header. I can do that today but it ends up as an input/output param that all my endpoints have to be aware of.
2 replies
I also would like the ability to have middlewear that injects things into inbound requests and ensures things are present on outbound requests. Ideally this would be transparent for the endpoint implementations. Right now, the only way I can see to do this ends up propogating everthing up and down the chain as input and output params (see my post just above this one).
1 reply
I guess this is typically termed middleware
Gourav Singh
@gschambial

Hi everyone,

while generating OpenAPI docs, my enums show up as:

properties:
        weekEnum:
          type: string
          enum:
          - SUNDAY
          - MONDAY
          - TUESDAY

and then I am using a codegen tool (autorest) to generate c# client. However, it generate my enum fields as strings. I found out that it needs extra information to be added for enums via extensions. I can see there are DocExtenions which can be used at enpoint level but I am wondering if there are Schema level extensions which I can use to add new properties to generated OpenAPI docs.

expected result is:

properties:
        weekEnum:
          type: string
          enum:
          - SUNDAY
          - MONDAY
          - TUESDAY
          x-ms-enum :
            modelAsString: false
            name: 'WeekEnum'
3 replies
Gilad Hoch
@hochgi

Hi, what would be an idiomatic way to define an endpoint for partially structured input?
What I mean by that is that I want to get a type like:

case class PartiallyStructured(text: String, number: Int, composite: AnotherCaseClass, freeStyleJsonObject: String)

But obviously I do want tapir to validate freeStyleJsonObject is a JSON object.
I know of a few ways to approach this, and I don't like any of 'em.

  1. I can of course use an existing JSON lib AST, and define freeStyleJsonObject: JsonObject - but that would mean enforcing whoever is using my endpoints lib (published to our nexus) as a "driver" to my service, to also pull in the full JSON lib.
  2. I can keep it as a string, and define the endpoint with in(jsonBody[PartiallyStructured].validate(…)), but validating means to parse the string, and make sure it is a valid JsonObject, which means again forcing users to pull in whatever lib I used to parse, and it's also not reflected in the type.
  3. I can validate only as part of serverLogic, but this would only be on the server side, and it is best if clients using sttp with published endpoints can do validations on their side before even sending the request.
  4. I can define my own zero dependencies JSON AST module, and use that, but really…? another "JSON lib" (even if it is just the AST) - feels a bit like: https://xkcd.com/927/

I should point out that the service(s) we build have the following structure:
project structure diagram

And that clients (other services) are written in different versions of scala.
Some still on 2.11. So we're cross building the endpoints with tapir 0.18.3 (we'll upgrade shortly to 0.19.x) for scala 2.12 & 2.13, and with tapir 0.8.11 for scala 2.11.

This is why it is important to me to pull as few as possible dependencies.

14 replies
Mikael Ståldal
@mikaelstaldal
Is it possible to use Tapir with Lift-json (which is supposed to be same as Json4s, but in a different package)?
5 replies
Piotr Buszka
@pbuszka

I have a service which signature has typed errors

endpoint
    .in("smthg")
    .get
    .errorOut(jsonBody[IError])

The service returns typed errors and everything works as expected when the error is generated by the service directly. However, it is is behind a load balancer and authorization proxy which both can generate errors like 503 or 403 with plain string description before it even reaches the service. So effectively the error type is a union String | IError.

For now I created a custom read codec which handles the problem on the client side but this is not a solution for a public client. Has anyone found a good way to manage such use case ?

7 replies
Swoorup Joshi
@Swoorup
anybody know how to websocket routes in swagger
when working with WebSocketBuilder2[F] => HttpRoutes[4] using http4s interpreter?
3 replies
Denis Savitsky
@Denis-Savitsky
Hi everyone!
Is there any way to put response header dynamically?
e.g. I want to put Location header in response and obviously the value is stored elsewhere
4 replies
Gastón Tonietti
@ktonga:matrix.org
[m]
Im using ReaderT[IO, MyEnv, A] as my F for http4s interpreter, the effect seems to run coz i see stuff saved in the db but the requests never complete, i have to cancel them after several seconds. What can it be?
6 replies
Sarpong Abasimi
@SarpongAbasimi

Hello everyone

I am using a type which uses java enums internally.

Example


public enum GroupFood {
    rice, pasta
}

case class FavFood(
    country: Countries,
    food: GroupFood
)
sealed abstract class Countries {
  val randomDoc: Int = 0
}

object Countries {
  implicit val codec: Codec[Countries] = deriveConfiguredCodec[Countries]


  case class BigCountry(
      name: Option[String],
      food: List[FavFood]
  ) extends Countries

  object  BigCountry {
    implicit val decoder: Decoder[ BigCountry] =
      deriveDecoder[ BigCountry]
    implicit val encoder: Encoder BigCountry] =
      deriveEncoder[ BigCountry].withDiscriminator
  }
}

Now if I have a type with this shape

 final case class MyRequest(country: Countries, flag: String)

Doing

  private val exportEndpoint =
    endpoint.post
      .in("countries")
      .in("food")
      .in(jsonBody[MyRequest])
      .errorOut(stringBody)
      .out(stringBody)

will cause an error like this

Could not find Schema for type MyRequest
Since 0.17.0 automatic derivation requires the following import: `import sttp.tapir.generic.auto._`
You can find more details in the docs: https://tapir.softwaremill.com/en/latest/endpoint/customtypes.html#schema-derivation
When using datatypes integration remember to import respective schemas/codecs as described in https://tapir.softwaremill.com/en/latest/endpoint/integrations.html
      .in(jsonBody[MyRequest])

How to do we go about deriving Schemas for java enums?

@adamw

7 replies
Gastón Tonietti
@ktonga:matrix.org
[m]
I found my problem and it turned out to be very bizarre, in case you are interested it was caused by this circe/circe#1829
1 reply
Gastón Tonietti
@ktonga:matrix.org
[m]
I is not a lock but an infinite recursion it seems
slavaschmidt
@slavaschmidt

Hello! In my endpoint, I need to reuse one of the headers in security and input, like in the definition below:

val correlationHeader = header[UUID]("correlation-id")

val ep = endpoint
   .get
   .securityIn(correlationHeader)
  .securityIn(auth.bearer[String]())
   .in(correlationHeader)

Unfortunately, this leads to the correlation-id header being defined twice in the open-api specification and the specification fails validation. Is this behaviour expected or should I create an issue? In the first case, what would be the recommended way to access the header without having it twice in the generated specification?

3 replies
slavaschmidt
@slavaschmidt

My API is required to log full request and response regardless of the content type and the (un)marshallability of the body. Additionally, I need to provide some context if the request was successfully parsed, something like this:

logInput(request: String, typedRequest: Option[RequestCaseClass]) = ???
logOutput(response: String, typedResponse: Option[ResponseCaseClass]) = ???

I would like to avoid having the plain request/response to appear anywhere in the generated api specification, what would be the best way to do this?
Ideally, I'd also like to avoid marshalling the response twice (once for logging and then again for the client), is there a way to do this as well?
Many thanks!

12 replies
Frank van Meeuwen
@fmeeuw

Hello, I am upgrading tapir to 0.19.0-M14 in our application, which uses http4s and zio, and noticed something strange. We have an internal endpoint which mixes both tapir routes and plain http4s routes. After updating the tapir routes to secure routes, the non-tapir routes now require an authentication header, and respond with "Invalid value for: header Authorization". If i define for example Tapir.routes <+> NonTapir.routes, the nonTapir routes would require authentication. A workaround I found is by putting the tapir routes last, e.g. NonTapir.routes <+> Tapir.routes it works as expected again.

Not sure what to do with this, should I create an issue, or perhaps something in our setup is causing this?

6 replies
MOHIT PRASANTH KALAHASTHI
@mohitprasanth

Is there a way in tapir to write a interceptor using which I can access the returned object from my Route and modify it accordingly ?
The Endpoint interceptor is giving me the ServerResponse, which is not I want. I want the Route response object i.e. before getting converted to server response.
Basically a Interceptor that gets triggered when ever my ResponseClass object is returned from any route.
so that I can modify this object and return back the modified response.
I have a usecase where I need to mask some data before returning.

more like, how Filters work in spring java.

4 replies
Alexey Novakov
@novakov-alexey
Hi everyone.
Tapir has AWS Lambda integration, which is nice. As I see it is based on AWS HTTP API request/response format. Can I make it work somehow easily with REST API request/response format? https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
7 replies
Kamil Kloch
@kamilkloch
Hello all, I am trying to set a cookie via .out(setCookie("cookie-name")). Server logic returns CookieValueWithMeta, but the cookie is missing in the response. I must be doing something wrong. Any ideas? Thanks!
Kamil Kloch
@kamilkloch
Update: my bad, "Set-Cookie" was not visible in Swagger. Scratch the question.
Michal Losiewicz
@mlosiewicz-pl

Hello,
I was using tapir successfully with 0.18.3 with some custom logic for proxying via sttp client in a generic manner with something like:

def toProxy[I, E, O](endpoint: Endpoint[I, E, O, Any], uri: Uri)(implicit params: ParamsAsArgs[I]): Route = {
    val request: I => Request[DecodeResult[Either[E, O]], Any] = SttpClientInterpreter().toRequest(endpoint, Some(uri))
    AkkaHttpServerInterpreter().toRoute(endpoint) { i =>
      params
        .applyFn(params.toFn(request), i)
        .send()
        .map(_.body match {
          case DecodeResult.Value(v) => v
          case err =>
            logger.error(s"Error while proxying request to ${uri} $err")
            throw new RuntimeException("Error while proxying")
        })
    }
  }

but after upgrading to 0.19.0 I don't see ParamsAsArgs anymore and I'm kind of lost in trying to make this work again in a generic way.
Any ideas?

Michal Losiewicz
@mlosiewicz-pl
nvm, found a way
2 replies
Tom Snee
@axtsnee
I have a custom 0.18.3 interceptor that extends UnsupportedMediaTypeInterceptor. I would like to write unit tests, but I find I need lots of collaborators (Responders, EndpointHandlers, etc.). I have two questions. (1) What is the easiest way to come up with instances of these collaborators? (2) Will this code change much when I upgrade to 0.19.0? If so, I might skip the unit tests for now.
Andy Czerwonka
@andyczerwonka

I'm having trouble with getting Tapir to generate the proper OpenAPI for a value type. E..g

final case class DataSourceId(value: String) extends AnyVal

I'd like the API to just deal with String. When I add examples, I get:

{
  "name": "Design Workflow",
  "branch_id": "0709e5a9-729e-499a-8b78-7164e42657fe",
  "design_space_id": "f8919d98-90f1-4ddd-8182-3af5cbb9ccec",
  "predictor_id": "c7f3e3d0-fd1d-4e37-bd34-484a27abcb0f",
  "datasource_id": {
    "value": "gemd::416ee981-23fc-4f61-b36f-8617c00b53c1::2"
  }
}

The data source is a value type with a bit of a DSL inside. I do have a custom schema. Yet, I still see that json in the example.

  implicit val dsIdSchema = Schema(SchemaType.SString[DataSourceId]())
    .format("One of gemd::{table_id}::{version} or csv::{path}::{file}")
    .description(s"An id representing either a `GEMD` data source or a `CSV` data source")
    .encodedExample("gemd::416ee981-23fc-4f61-b36f-8617c00b53c1::2")
    .validate(idValidator)
4 replies
Dennis Fung
@defung
Hi! I'm using Tapir 0.18.3 (just upgraded from 0.16.16), and I'm building out a Schema for one of my custom case classes, which is defined as a SchemaType.SProduct, which now takes a SchemaType.SProductField instead of a tuple. I'm having trouble understanding what the get field is supposed to be here, and was hoping someone can help me understand what I need to put for this:
https://github.com/softwaremill/tapir/blob/v0.18.3/core/src/main/scala/sttp/tapir/SchemaType.scala#L67
1 reply
Jens Grassel
@jan0sch
Just dropping by to congratulate on the release of 0.19.0 and thank everyone involved! :star: :heart_eyes_cat:
1 reply
Charles Coombs-Esmail
@ccoombsesmail
Hello. I'm using Tapir 0.19.0 with zioHttp. I am getting a 413 payload too large error and was wondering if there is a way to increase the max payload size limit
2 replies
Gilad Hoch
@hochgi

Hi,
POST CSV endpoint - is there a good example for this?
Ideally, I would want to start processing request entity as a stream, and not load entire CSV in memory.
In pure akka-http, this is easy, since entity.dataBytes is already a Source[ByteString, Any].
headers are known (so schema can enforce it, if this is possible).
Not sure how it'll be represented in swagger though.

Any tips & helpful links are greatly appreciated,
Thanks :)

8 replies
Grant
@gavares
I’d like to generate prevPage and nextPage links I can send back to a caller from a list endpoint. In Play! I would use a reverse router to safely generate the urls. The closest thing I’ve managed to find with Tapir is something like endpoint.renderPathTemplate(). I also briefly looked at using an SttpClientInterpreter and trying to extract the URL from there instead of actually making a call but I didn’t get very far with that either.
2 replies
Mark de Jong
@Fristi
Hello! Congrats on the release of version 0.19! We found out that tapir-swagger-ui-http4s is still stuck on 0.19-M4, is this intended?
3 replies
Tom Snee
@axtsnee
I think it has been replaced by tapir-swagger-ui-bundle. See https://tapir.softwaremill.com/en/latest/docs/openapi.html.
Akshay Deshpande
@akshay-d29
Hello, I'm using tapir-swagger-ui and have a GET endpoint with some jsonBody. On the swagger UI on issuing the request, the generated curl when executed returns the right response but the swagger UI shows response as TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.. How do I fix this?
1 reply
Veysi Ertekin
@veysiertekin
Hi,
Is tapir supports static documentation generation? As far as I can see it has yaml file content generation utilities. Is it possible to export with Swagger UI resources etc? or do we need some manual operation for that :)
3 replies
ex0ns
@ex0ns
Hello ! I need to be able to dump all requests made to my server into a database, I was thinking about writing a custom interceptor (Request interceptor if I understood the doc correctly) but I don't really know where to start from here, do you happen to have an example or a project that is already doing something similar ? I think this is pretty specific to the backend I'm using (akka)
13 replies
johnhungerford
@johnhungerford
Hi all! Is there a schema type that can include both enumerated fields and open fields as well? (e.g., additionalProperties in an openapi spec.) I see that there is an SProduct and SOpenProduct, but I don't see any schema that combines the two. I would like to use a case class with one field of type Map[String, Int] which would correspond to all the additional fields in a json object.
1 reply
QuadStingray
@QuadStingray

Hi all,
I have a Problem with the new .serverSecurityLogic. I need a path Variable in my security method, but now the server did not find the route.
Sample Definition

 val debugSystemSettings = endpoint
    .securityIn(token)
    .securityIn(bearer)
    .securityIn("user")
    .securityIn(path[String]("userId"))
    .in("settings")
    .out(jsonBody[DebugInfo])
    .summary("Debug Info zum Service")
    .description("")
    .name("debugSetting")
    .tag("Debug")
    .method(Method.GET)
    .errorOut(errorEndpointDefinition)
    .serverSecurityLogic(parameter => authorize(parameter))
    .serverLogic(authInfo => parameter => serviceDebugInfo(authInfo, parameter)

The Swagger UI shows the route rightly with /user/{userId}/settings, but the Akka-Http answers with an error. Did I something wrong?

8 replies
Gilad Hoch
@hochgi

Hi, I'm getting a weird exception involving magnolia macro for a custom codec used in my tapir endpoints.
The stacktrace: https://gist.githubusercontent.com/hochgi/ac6e9ab1a1477070726ff191700a23a8/raw/1a53e4bd6384c002d780c40181049b70cf0da4ea/tapir-magnolia-error.stacktrace
The line written that appears to be causing the error at kaas.evmgr.endpoints.Snippet$.$anonfun$snippetCodec$23(Snippet.scala:70)
seems harmless:

val snippetCodec: JsonCodec[dt.Snippet] = {
  val decode: String => DecodeResult[dt.Snippet] = s => parse(s) match {
    case Left(ParsingFailure(_, ex)) => DecodeResult.Error(s, ex)
    case Right(circeJson) => decodeSnippetJson(s, circeJson)
  }
  val encode: dt.Snippet => String = appendSnippetToWriter(new StringBuilderWriter()).andThen(_.toString)
  Codec.json[dt.Snippet](decode)(encode) // <<-- This is line 70
}

I latter use this in an endpoint ….in(customJsonBody[dt.Snippet](snippetCodec)).….

Any idea what I may have done wrong? Or how to fix?
Thanks!

counter2015
@counter2015
Hi, is there any thing like TapirOpenAPICirceDecoders? I found TapirOpenAPICirceEncoders in tapir-openapi-circe, and I want parse json to sttp.tapir.openapi.OpenAPI
1 reply
Tom Snee
@axtsnee
I would like to log "expected" errors (i.e. the server logic returns an E value) even when the endpoint has an errorOut for that particular E. DefaultServerLog's logLogicExceptions = true does not seem to do it. What is the easiest way to achieve this?
4 replies
Gilad Hoch
@hochgi

@adamw I created a repo reproducing my error:
https://github.com/hochgi/tapir-bug-repro

Would you like me to open an issue referencing this repro?

3 replies