Multi param query parameters in Tapir

Hello, I’m trying to define a Tapir endpoint that has two OptionalMultiQueryParamDecoderMatcher query parameters.

Let’s say one parameter has the name id and the other name, such that I could call the endpoint with something like:

GET /find?id=1a&id=1b&name=foo&name=bar

I have a HTTP4S route that works with this using OptionalMultiQueryParamDecoderMatcher[String]("id"), which can then be mapped to a List[String]

I would really like to do this with Tapir, but I’m having difficulty finding examples or documentation for such a solution ( copilot isn’t helping either :wink: )

Any suggestions?

Can you try adding an input which decodes to a list, i.e. query[List[String]]("id")?

Hi @adamw and thanks for the reply. This is what I’ve ended up doing, let me know if this seems wrong:

val getIdentitiesWithIdentityAndLead: PublicEndpoint[QueryParams, String, List[MyType], Any] =
    endpoint.get
      .in("myEndpoint")
      .in(queryParams)
      .out(jsonBody[List[Identity]])
      .errorOut(jsonBody[String])

Then used that with:

endpoints.getIdentitiesWithIdentityAndLead.serverLogicSuccess { params =>
    val ids = optionalSeqToList(params.getMulti("id"))
    val names = optionalSeqToList(params.getMulti("name"))
    .
    .

As a side, optionalSeqToList is just:

def optionalSeqToList[T](seq: Option[Seq[T]]): List[T] = seq.getOrElse(Seq.empty).toList

That doesn’t appear to work. While the request contains multiple values with the same key, the parameters picked up on the server only sees the last one

@adamw your way worked! I just needed to build the Codecs correctly. Thank you!

Oh, what did you have to change in the codecs? For me it simply worked with query[List[String]]("id").

By the way, the approach with queryParams would work as well, but the documentation wouldn’t be precise - the id parameter wouldn’t get listed there, as the documentation interpreter would have no way of knowing that you’re using such a parameter.

I have an opaque type, so I needed to create some codecs, but once that was done everything worked like a charm.

Thanks again!