Combining different "mount points" in the same Swagger UI

Hello :slight_smile:

I currently have the following code:

  val rootSwaggerEndpoints = SwaggerInterpreter().fromServerEndpoints[MyIO](root.all, "My API", "1.0")
  val rootEndpoints        = root.all ++ rootSwaggerEndpoints
  val apiv4SwaggerEndpoints = SwaggerInterpreter(swaggerUIOptions =
    SwaggerUIOptions.default.contextPath(List("api", "4"))
  ).fromServerEndpoints[MyIO](apiv4.all, "My API", "1.0")
  val apiv4Endpoints = apiv4.all ++ apiv4SwaggerEndpoints

  val rootRoutes: HttpRoutes[MyIO]  = ZHttp4sServerInterpreter().from(rootEndpoints).toRoutes
  val apiv4Routes: HttpRoutes[MyIO] = ZHttp4sServerInterpreter().from(apiv4Endpoints).toRoutes
  val router: HttpRoutes[MyIO]      = Router("/" -> rootRoutes, "/api/4" -> apiv4Routes)

This makes it so I have two docs endpoints, one mounted on / and one mounted on /api/4. Is there a nice way to make it so all endpoints appear in /docs, but have the apiv4SwaggerEndpoints have the /api/4/ prefix to them? As you can see, I had to add a contextPath to my apiv4SwaggerEndpoints, as Swagger sent requests to /, even though the docs were on /api/4.

Thanks! :pray:

The context path setting is not relevant if you use relative paths. If I understand your desired layout correctly (you want to add a server to openapi which will point to /api/v4), this can be done by modifying the options as follows:

SwaggerUIOptions.default.contextPath(List("api", "4")).withAbsolutePaths

Let me know if this works :slight_smile:

Thanks for your replay, Adam!

Adding .withAbsolutePaths didn’t seem to do anything other than change the location of the YAML file, from what I can tell. I think I didn’t quite explain what I’m trying to do, so I’ll try again :slight_smile:

Currently, I have two docs endpoints: /api/4/docs (shown below)

And /docs (shown below)

What I’m trying to do is a have a single docs endpoint, to be mounted on the root route (so /docs), and that it will have the endpoints of both screenshots, with routes preceded with /api/4 showing as such in Swagger.

Thanks again! :pray:

Ah I see :slight_smile: I think the simples solution could be to generate the docs from endpoints which are prefixed with api/v4. Sth like:

val apiv4SwaggerEndpoints = SwaggerInterpreter()
  .fromEndpoints[IO](apiv4.map(_.endpoint.prependIn("api" / "v4")), "My API", "1.0")

Note that I don’t think you need the contextPath setting, as it’s a no-op in your case.

1 Like

Ah, that _.endpoint.prependIn was what I was missing! Thank you very much, Adam! And while I’m at it, tapir made a great impression at work today, after adding 3 lines of code and getting a documented Swagger UI for free :wink:

1 Like