doc-generate/MIGRATION.md

6.2 KiB

🔄 Migration Guide: From go-zero Plugin to Standalone Tool

This document explains how go-doc was extracted from go-zero and made independent.

📊 What Changed?

1. Module Independence

Before (go-zero plugin):

// Part of go-zero's internal tools
package swagger // in tools/goctl/api/plugin/swagger/

After (standalone):

module go-doc

package swagger // in internal/swagger/

2. Dependency Reduction

Removed Internal Dependencies

Dependency Replaced With Reason
go-zero/tools/goctl/internal/version Custom version in main.go Internal package not accessible
go-zero/tools/goctl/util go-doc/internal/util Self-contained utilities
go-zero/tools/goctl/util/stringx go-doc/internal/util Custom string manipulation
go-zero/tools/goctl/util/pathx go-doc/internal/util Custom path utilities
google.golang.org/grpc/metadata Direct map access Simplified KV retrieval

Kept Essential Dependencies

require (
    github.com/go-openapi/spec v0.21.0           // Swagger spec
    github.com/spf13/cobra v1.8.1                // CLI framework
    github.com/zeromicro/go-zero/tools/goctl v1.9.0  // API parser only
    gopkg.in/yaml.v2 v2.4.0                      // YAML output
)

3. Project Structure

Before:

go-zero/
└── tools/
    └── goctl/
        └── api/
            └── plugin/
                └── swagger/
                    ├── swagger.go
                    ├── parameter.go
                    └── ...

After:

go-doc/
├── cmd/
│   └── go-doc/
│       └── main.go          # Standalone entry point
├── internal/
│   ├── swagger/             # Core logic (from go-zero)
│   │   ├── swagger.go
│   │   ├── parameter.go
│   │   └── ...
│   └── util/                # Self-contained utilities
│       ├── util.go
│       ├── stringx.go
│       └── pathx.go
└── example/

4. Import Path Changes

Before:

import (
    "github.com/zeromicro/go-zero/tools/goctl/util"
    "github.com/zeromicro/go-zero/tools/goctl/util/stringx"
    "github.com/zeromicro/go-zero/tools/goctl/internal/version"
    "google.golang.org/grpc/metadata"
)

After:

import (
    "go-doc/internal/util"
)

5. Metadata Handling

Before (using gRPC metadata):

func getStringFromKV(properties map[string]string, key string) string {
    md := metadata.New(properties)
    val := md.Get(key)
    if len(val) == 0 {
        return ""
    }
    return val[0]
}

After (direct map access):

func getStringFromKVOrDefault(properties map[string]string, key string, def string) string {
    if len(properties) == 0 {
        return def
    }
    val, ok := properties[key]
    if !ok {
        return def
    }
    str, err := strconv.Unquote(val)
    if err != nil || len(str) == 0 {
        return def
    }
    return str
}

6. Version Information

Before:

ext.Add("x-goctl-version", version.BuildVersion)
ext.Add("x-github", "https://github.com/zeromicro/go-zero")

After:

ext.Add("x-generator", "go-doc")
ext.Add("x-github", "https://github.com/danielchan-25/go-doc")

🔧 Implementation Details

Custom Utilities Created

1. util.TrimWhiteSpace

// Replaces: go-zero/tools/goctl/util.TrimWhiteSpace
func TrimWhiteSpace(s string) string {
    return strings.Map(func(r rune) rune {
        if unicode.IsSpace(r) {
            return -1
        }
        return r
    }, s)
}

2. util.FieldsAndTrimSpace

// Replaces: go-zero/tools/goctl/util.FieldsAndTrimSpace
func FieldsAndTrimSpace(s string, fn func(rune) bool) []string {
    fields := strings.FieldsFunc(s, fn)
    result := make([]string, 0, len(fields))
    for _, field := range fields {
        trimmed := strings.TrimSpace(field)
        if len(trimmed) > 0 {
            result = append(result, trimmed)
        }
    }
    return result
}

3. util.String (for ToCamel/Untitle)

// Replaces: go-zero/tools/goctl/util/stringx
type String struct {
    source string
}

func From(s string) String {
    return String{source: s}
}

func (s String) ToCamel() string { /* implementation */ }
func (s String) Untitle() string { /* implementation */ }

4. util.MkdirIfNotExist

// Replaces: go-zero/tools/goctl/util/pathx.MkdirIfNotExist
func MkdirIfNotExist(dir string) error {
    if _, err := os.Stat(dir); os.IsNotExist(err) {
        return os.MkdirAll(dir, 0755)
    }
    return nil
}

Compatibility

What's Still Compatible?

API File Format - 100% compatible with go-zero .api files
Swagger Output - Generates identical OpenAPI 2.0 specifications
All Features - All swagger generation features preserved
Tag Syntax - Same tag options (range, enum, default, example, etc.)

What's Different?

⚠️ Generated Metadata

  • x-generator: "go-doc" instead of x-goctl-version
  • x-github points to go-doc repository
  • Build date format remains the same

⚠️ Module Name

  • Import as go-doc not part of go-zero

⚠️ Binary Name

  • go-doc instead of goctl api plugin -plugin swagger

🚀 Migration Steps for Users

If you were using go-zero's swagger plugin:

Old Way (go-zero plugin):

goctl api plugin -plugin swagger -api example.api -dir output

New Way (standalone go-doc):

go-doc -a example.api -d output

📝 Benefits of Independence

  1. Smaller Binary - Only swagger generation, no full goctl
  2. Faster Installation - Fewer dependencies
  3. Clearer Purpose - Single responsibility
  4. Easier Maintenance - Self-contained codebase
  5. Flexible Updates - Independent release cycle

🙏 Attribution

This tool was extracted from the excellent go-zero project. We are grateful to the go-zero team for their foundational work.


Original Source: https://github.com/zeromicro/go-zero/tree/master/tools/goctl/api/plugin/swagger
License: MIT (both original and this project)