Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

39 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

GoSemRoute (gswr)

Golang OpenAPI

Semantic OpenAPI generator for Go projects.

GoSemRoute focuses on semantic recognition, not only annotation parsing.
It walks routing code, follows helper wrappers, and infers request/response schemas from real code paths.

Status

  • Supported:
    • echo v5 / v4
    • gin
  • Planned:
    • fiber
    • chi

This tool is optimized for real internal codebases, but it is still static analysis.
If you hit unsupported patterns, open an issue with a minimal code sample.

Web API reference UI

Use the gswr web command in the project root directory to start an embedded API reference UI.

web

Quick Start

Install CLI:

go install github.com/arsfy/gswr/cmd/gswr@latest

Run:

Generate YAML:

gswr generate
# short alias
gswr g

gswr automatically discovers package main / func main() and, when a project has multiple binaries, selects the only entry that produces API routes. You can also scan another project directory or explicitly resolve ambiguity:

gswr g ../my-service
gswr g --entry ./cmd/control-api/main.go

Generate JSON:

gswr g --out docs/openapi.json

Force format explicitly:

gswr --entry ./main.go --out docs/openapi.out --format json
gswr --entry ./main.go --out docs/openapi.out --format yaml

Open the embedded API reference UI:

gswr web
# scan another project
gswr web ../my-service
# custom bind address and starting port
gswr web --host 0.0.0.0 --port 45000

The command starts at http://127.0.0.1:43877 and opens it in the default browser.

Upgrade a CLI installed with go install:

gswr upgrade

The command checks the latest GitHub Release and installs that concrete version. Locally built or manually downloaded binaries are left untouched and must be updated manually from GitHub Releases.

Why Semantic Recognition

Most generators rely heavily on doc comments.
GoSemRoute additionally infers API shape from code semantics, so it can still produce useful docs with partial or missing annotations.

Core Capabilities

  • Route discovery with nested Group(...) recursion and cross-file router chaining
  • Input inference from Param, QueryParam, QueryParamOr, FormValue, FormValueOr
  • Bind(&req) inference via param/query/header/json tags and required constraints
  • Field visibility via the openapi struct tag (-, readOnly, writeOnly)
  • OpenAPI 3.1 schemas with nullable pointer types, UUID format inference, and base64 []byte encoding
  • Response inference from direct c.JSON(...) returns and helper wrappers like resp.Success(...)
  • Multi-exit response collection (return in different branches)
  • Type inference across nested structs, map literals, and helper argument binding
  • Authentication inference from middleware semantics (bearer, cookie, header apiKey)
  • Tag support via explicit @Tags / @tag and automatic path-based fallback grouping

Annotation Support

  • Operation: @summary / @Summary, @description / @Description, @tag / @tags / @Tags
  • Main metadata: @title, @version, @description, @BasePath / @basepath, @host, @schemes

Field Visibility (openapi struct tag)

Struct fields can be hidden from or annotated in the generated schema with an openapi struct tag. It is independent of encoding/json, so adding it never changes runtime (de)serialization.

Tag Effect
openapi:"-" Omit the field from request, response and component schemas. Use this for internal config that is exchanged between the control plane and edge nodes but is not part of the public API.
openapi:"readOnly" Emit the field with the native OpenAPI readOnly: true flag (present in responses, ignored on writes).
openapi:"writeOnly" Emit the field with the native OpenAPI writeOnly: true flag (present in requests, ignored on reads).
type WAFPolicy struct {
    Enabled       bool   `json:"enabled"`
    GeoIPDatabase string `json:"geoip_database,omitempty" openapi:"-"` // control-plane internal
}

readOnly/writeOnly are kept as native Schema Object flags instead of stripping the field at the request/response stage: gswr caches one component per package+type, and the same type is typically shared between request and response bodies. Removing the field would corrupt the shared component, whereas readOnly/writeOnly annotate it without conflict.

OpenAPI 3.1 Schema Mapping

Generated documents use OpenAPI 3.1.0 and its JSON Schema vocabulary. Go pointer fields are nullable, []byte is represented as a base64-encoded string, and UUID types from common UUID packages use format: uuid.

Go type OpenAPI 3.1 schema
*string type: [string, "null"]
*MyStruct anyOf: [$ref, {type: "null"}]
[]byte / []uint8 type: string, contentEncoding: base64
uuid.UUID type: string, format: uuid

Example Pattern (Helper Wrappers)

GoSemRoute can infer response schema through helper layers:

func Success(c *echo.Context, data any) error {
  return c.JSON(http.StatusOK, types.Response{Code: "ok", Data: data})
}

func List(c *echo.Context) error {
  id, _ := ParseIDParam(c, "id")
  return Success(c, map[string]any{
    "id": id,
  })
}

Generated 200 schema will include a typed data.id field instead of a generic object.

Example API

package resp is a secondary abstraction layer for input and output handling.

// @summary Edit user
// @description Edits user profile fields with helper-based parsing.
// @Tags user
func edit(c *echo.Context) error {
	id, _ := resp.ParseIDParam(c, "id")
	age := resp.ParseIntForm(c, "age", 18)
	email := c.FormValueOr("email", "default@example.com") // Description πŸŽ‰

	if id <= 0 {
		return resp.BadRequest(c, "id <= 0")
	}

	return resp.Success(c, map[string]any{
		"id":  id,
		"age": age,
		"email": []string{
			email,
		},
	}) // Response Description πŸŽ‰
}
/api/v1/user/{id}:
    post:
        operationId: edit
        summary: Edit user
        description: Edits user profile fields with helper-based parsing.
        tags:
            - user
        security:
            - header_Authorization: []
        x-middlewares:
            - AuthMiddleware
        parameters:
            - name: id
                in: path
                required: true
                schema:
                type: number
            - name: age
                in: query
                schema:
                type: number
            - name: email
                in: query
                description: "Description πŸŽ‰"
                schema:
                type: string
        responses:
            "200":
                description: "Response Description πŸŽ‰"
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                code:
                                    type: string
                                    enum:
                                        - ok
                                data:
                                    type: object
                                    properties:
                                        age:
                                            type: number
                                        email:
                                            type: array
                                            items:
                                                type: string
                                        id:
                                            type: number
                                    required:
                                        - age
                                        - email
                                        - id
            "400":
                description: Client Error
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                code:
                                    type: string
                                    enum:
                                        - id <= 0

Current Limitations

  • Dynamic runtime-only patterns (reflection-heavy dispatch, generated handlers) may not be fully resolved
  • Ambiguous symbols with no import/type context may degrade to generic object schema
  • This is static analysis, not runtime tracing

Development

Run tests:

go test ./...

Rebuild the frontend assets embedded by the CLI:

cd web
pnpm build

About

πŸ–‡οΈ Semantic OpenAPI generator for Go projects, focuses on semantic recognition, not only annotation parsing. It walks routing code, follows helper wrappers, and infers request/response schemas from real code paths.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages