Logo

dev-resources.site

for different kinds of informations.

Versioning in Go Huma

Published at
1/10/2025
Categories
go
documentation
Author
Philip Perry
Categories
2 categories in total
go
open
documentation
open
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"

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)

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)

Featured ones: