Supporting Tag Groups

Hello,

Redoc supports the x-tagGroup extension, which gives an additional layer of nesting in the endpoints column on the left hand-side of the generated website. See the pet store example:

I’m aware that I can extend the generated documentation with some primitive types, e.g keys with lists of strings etc. but how would I go about creating the tag group object?

I would have thought a case class with a Circe encoder/decoder would suffice but unfortunately not.

Any help would be greatly appreciated :pray:

@gerryfletch I have just tried to add this extension in a pet project, and it works as expected.

  1. Define a case class for tag groups
  case class TagGroupDocExtension(name: String, tags: List[String])
  1. Build a list of groups:
  val tagGroupsExtension =
    DocsExtension.of(
      "x-tagGroups",
      List(
        TagGroupDocExtension(
          "General",
          List("pet", "store")
        ),
        TagGroupDocExtension("User Management", List("user"))
      )
    )
  1. Annotate your endpoints with tags
  val exampleEndpoint: sttp.tapir.Endpoint[Unit, Example, String, String, Any] = endpoint.get
    .in("test" / path[Example]("testId"))
    .out(stringBody)
    .errorOut(stringBody)
    .tag("store")

Make sure all tags listed in tagGroupsExtension are used in your endpoints.

  1. Define documentation endpoints, referring to tagGroupsExtension
  val docEndpoints: List[ServerEndpoint[Any, IO]] = RedocInterpreter()
    .fromServerEndpoints[IO](apiEndpoints, Info("title", "version"), List(tagGroupsExtension))

Note: If you additionally use OpenAPIDocsInterpreter to create a yaml file, please note that the extensions will be specified in the end of the specs file.

  1. Bind your endpoints and start the server, the groups should be visible in the redoc UI.

@kciesielski do you mind sharing your imports for that snippet?

That’s precisely what I tried before, but couldn’t get the JsonCodec stuff to work:

Cannot find a codec between types: String and List[TagGroupDocExtension], formatted as: sttp.tapir.CodecFormat.Json

Sure, here are the imports I used to get circe generic autoderivation, Tapir schema generic autoderivation, and Tapir<>circe interop

import io.circe.generic.auto.*
import sttp.tapir.generic.auto.*
import sttp.tapir.json.circe.*

I must have been missing an import there - working a charm now, thanks ever so much @kciesielski !

1 Like