DEV Community

Philip Perry
Philip Perry

Posted on

Versioning in Go Huma

We want to have a separate documentation for each version in Go Huma, e.g. /v1/docs, /v2/docs, etc.

This can be done by setting the docs path like this:

config.DocsPath = "/{version}/docs"
Enter fullscreen mode Exit fullscreen mode

We can use middleware to get the version from the path in the request and load the description used in the docs depending on the version:

config := huma.DefaultConfig("API V"+versionNumberString, versionNumberString+".0.0")
                overviewFilePath := filepath.Join("/app/docs", fmt.Sprintf("v%s", versionNumberString), "overview.md")
                overview, err := ioutil.ReadFile(overviewFilePath)
                if err != nil {
                    log.Fatalf("Error reading file: %v", err)
                }

                config.Info.Description = string(overview)
Enter fullscreen mode Exit fullscreen mode

And we can import all routes that we want to display in the docs based on the version. This will also load them so that they can be used as actual endpoints.

This is the complete code for routing:

router := chi.NewMux()
    router.Use(func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            urlPathParts := strings.Split(r.URL.Path, "/")
            versions := []string{"v1", "v2", "v3"}
            if helpers.Contains(versions, urlPathParts[1]) {
                versionPath := urlPathParts[1]
                if versionPath == "" {
                    http.Error(w, "version does not exist", http.StatusInternalServerError)
                }
                versionNumberString := strings.TrimPrefix(versionPath, "v")
                versionNumber, _ := strconv.Atoi(versionNumberString)
                config := huma.DefaultConfig("API V"+versionNumberString, versionNumberString+".0.0")
                overviewFilePath := fmt.Sprintf("docs/v%s/overview.md", versionNumberString)
                overview, err := ioutil.ReadFile(overviewFilePath)
                if err != nil {
                    log.Fatalf("Error reading file: %v", err)
                }

                config.Info.Description = string(overview)
                api := humachi.New(router, config)

                switch versionNumber {
                case 1:
                    api = v1handlers.AddV1Middleware(api)
                    v1handlers.AddV1Routes(api)
                case 2:
                    api = v2handlers.AddV2Middleware(api)
                    v2handlers.AddV2Routes(api)
                default:
                    api = v3handlers.AddV3Middleware(api)
                    router = v3handlers.AddV3ErrorResponses(router)
                    v3handlers.AddV3Routes(api)
                }
            }

            next.ServeHTTP(w, r)
        })
    })

    config := huma.DefaultConfig("API V3", "3.0.0")
    config.DocsPath = "/{version}/docs"

    humachi.New(router, config)
Enter fullscreen mode Exit fullscreen mode

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more