fastify / help

Need help with Fastify? File an Issue here.
https://www.fastify.io/
65 stars 8 forks source link

Grouping endpoints by api versioning and then for their tags #944

Open nickolasdeluca opened 1 year ago

nickolasdeluca commented 1 year ago

💬 How to achieve endpoint grouping by version and then their tags?

I'd like my routes to be shown in swagger like this: /v1/routeA /v1/routeB

-- v1
|--- routeA
|--- routeB

/v2/routeA /v2/routeB

-- v2
|--- routeA
|--- routeB
|--- routeC

This has somewhat been answered with this PR. I tried the following code:

fastify.register(fastifySwagger, {
  openapi: { 
    //some  configs
  },
  transform: ({ schema, url, route, openapiObject }) => {
    schema.tags = [route.prefix];
    return schema;
  },
});

The best I could achieve with this code was an auto-mapping of the endpoints based on their routes, it ended up like this:

--- /v1/routeA
--- /v1/routeB
--- /v2/routeA
--- /v2/routeB
--- /v2/routeC

But that's not exactly what I wanted. I need to group them by api version spec like this:

-- v1
|--- routeA
|--- routeB
-- v2
|--- routeA
|--- routeB
|--- routeC

Anyone has any idea on how to achieve this?

My Environment

nkwib commented 4 months ago

If the issue is setting up tags, swagger will take care of that as long as the schema includes a tags key:

fastify.get(
  "/routeA",
  { schema: { tags: ["v1"] } },
  async (request, reply) => {
    // routeA logic
  }
);

If instead you wanted to remove the /v1 from your routes under the v1 tag, this is quite hacky but with some DOM manipulation you can achieve removing the v[number] from the path without breaking other swagger functionalities:

when you register SwaggerUI you can specify any javascript function to run on the onComplete event:

await fastify.register(swaggerUi, {
    routePrefix: "/documentation",
    uiConfig: {
      docExpansion: "full",
      deepLinking: false,
      onComplete: function () {
        const modifyPaths = () => {
          // Modify the paths in the UI
          document
            .querySelectorAll(".opblock-summary-path")
            .forEach((element) => {
              const originalPath = element.getAttribute("data-path");
              if (
                originalPath &&
                !element.classList.contains("path-modified")
              ) {
                const newPath = originalPath.replace(/^\/v[0-9]+/, "");
                element.innerText = newPath;
                element.classList.add("path-modified"); // Add a class to the element to prevent re-modification
              }
            });
        };

        // Initial path modification
        modifyPaths();

        // Setup MutationObserver to watch for changes in the DOM
        const observer = new MutationObserver((mutations) => {
          mutations.forEach((mutation) => {
            if (mutation.type === "childList" && mutation.addedNodes.length) {
              modifyPaths();
            }
          });
        });

        // Start observing the document for added nodes
        observer.observe(document.body, {
          childList: true,
          subtree: true,
        });
      },
    },
  });

The result is the following:

Image