[BUG] Default `CommaSeparated[String]` / `Delimited[",", String]` results in single value rather than list of values (OpenAPI)
jnatten opened this issue · comments
Tapir version: 1.9.11
Scala version: 2.13.13
If i define an endpoint with a query parameter with type CommaSeparated[String]
and a default value like Delimited[",", String](List("a", "b", "c"))
the actual default value result in openapi default value like this: "default": ["a,b,c"]
rather than what i expected: "default": ["a","b","c"]
If the default list is empty the generated doc is "default": [""]
which results in our swagger-ui defaulting to a single empty element in list.
I work around it by using Option[CommaSeparated[String]]
and defaulting to None
, but it isn't perfect 😄
How to reproduce?
Code example with openapi endpoint
import io.circe.syntax.EncoderOps
import sttp.apispec.openapi.{Components, Info}
import sttp.tapir._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.server.jdkhttp.{Id, JdkHttpServer, JdkHttpServerOptions}
import sttp.apispec.openapi.circe._
import sttp.tapir.model.{CommaSeparated, Delimited}
import java.util.concurrent.Executors
object Main {
def main(args: Array[String]): Unit = {
val endpoints: List[ServerEndpoint[Any, Id]] = List(
endpoint.get
.description("Hello this is some endpoint")
.in("hello")
.in(query[CommaSeparated[String]]("some-list").default(Delimited[",", String](List("a", "b", "c"))))
.out(stringBody)
.serverLogicPure { someList =>
Right(s"Yay, ${someList.values.map(e => s"'$e'")}!")
}
)
val docs = {
val info = Info(title = "testapi", version = "1.0")
val docs = OpenAPIDocsInterpreter().serverEndpointsToOpenAPI(endpoints, info)
val generatedComponents = docs.components.getOrElse(Components.Empty)
val docsWithComponents = docs.components(generatedComponents).asJson
docsWithComponents.asJson
}
def swaggerEndpoint: ServerEndpoint[Any, Id] = endpoint.get
.in("api-docs")
.out(stringJsonBody)
.out(header("Access-Control-Allow-Origin", "*"))
.serverLogicPure { _ => Right(docs.noSpaces) }
val executor = Executors.newVirtualThreadPerTaskExecutor()
val opts = JdkHttpServerOptions.Default
val server = JdkHttpServer()
.options(opts)
.addEndpoints(endpoints :+ swaggerEndpoint)
.executor(executor)
.port(8080)
.start()
synchronized(wait())
}
}
I'm surprised you got any default entry in the schema at all - when I tried to reproduce, the default was missing entirely, only after removing some duplicate code in #3584 all the attributes are properly copied.
However, the problem remains - I still get the encoded form in the default entry - which is expected, since all defaults values are always encoded (and the encoded form of the query parameter is a "glued" string). I'll think what we can do about that :)