Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fibgen

Generate a complete OpenAPI document (3.1 and 3.0) for Go + Fiber services through static analysis.

No annotations, no // @Summary comments, no code generation, no changes to your handlers. Point fibgen at an existing project and get a spec with paths, parameters, request bodies, per-status responses, and fully resolved type schemas ($ref, enums, nullables).

Supports Fiber v2 and v3.

Go Reference


Why static analysis

Every Fiber handler is just func(c fiber.Ctx) error (v3) or func(c *fiber.Ctx) error (v2). The request and response types exist only as local variables inside the body (c.Bind().Body(&dto), c.JSON(user)). The signature is opaque, so runtime reflection yields nothing useful.

The only way to get "fully automatic, on unmodified code" is to analyze the code itself with go/packages + go/types: find the route registrations, follow them into the handler body, and recover the types from the c.* calls.

Install

go install github.com/nyawave/fibgen/cmd/fibgen@latest

Or build from source:

git clone https://github.com/nyawave/fibgen
cd fibgen
./build.sh           # -> ./bin/fibgen   (build.bat on Windows)

Usage

# from the root of the project you want to document
fibgen ./... > openapi.yaml

# explicit options
fibgen -dir ./myservice -o openapi.json --openapi-version 3.0 ./...

Flags

Flag Default Description
-o stdout output file; extension (.yaml / .json) selects the format
-format from -o, else yaml output format: yaml | json
-dir . project directory to analyze
--openapi-version 3.1 spec version: 3.1 or 3.0
--title module name API title
--doc-version 0.1.0 API document version
--quiet false suppress diagnostics on stderr

Anything the analyzer cannot resolve statically is reported on stderr as note: ... (suppress with --quiet).

What it detects

Routes

  • app.Get/Post/Put/Delete/Patch/Head/Options/Connect/Trace, All, Add(method, path, ...)
  • Group(prefix) with arbitrary nesting; prefixes are resolved through variable assignments and through routers passed as function parameters
  • Fiber paths → OpenAPI paths: :id{id}, :id? (optional), :id<int> (constraint maps to a type), * / + (wildcards)

Handlers (resolved to a function body)

  • named functions, controller method values (ctrl.Create), inline closures, function-typed variables, and statically resolvable handler factories (makeHandler(service))
  • project helper functions that receive the active Fiber context; actual arguments are propagated so respond(c, value) retains the concrete response type

Requests

  • body: c.BodyParser(&dto) (v2), c.Bind().Body(&dto) / .JSON(&dto) (v3)
  • query: c.QueryParser(&s) / c.Bind().Query(&s) (struct expansion via query: tags), and c.Query/QueryInt/QueryBool/QueryFloat("name")
  • path: from the route template, with the type upgraded by c.ParamsInt("id")
  • header: c.ReqHeaderParser(&s), c.Bind().Header(&s), c.Get("X-...")

Responses

  • c.JSON(x) / c.XML(x) → schema of x, status 200
  • c.Status(code).JSON(x) → status from code (literal or fiber.StatusCreated)
  • c.SendStatus(code), c.SendString(...), c.Status(code).Send..., c.Redirect(...)
  • multiple response shapes per status — when a handler returns different types depending on a flag (e.g. a short vs. full object on ?short=true), the alternatives are collected into a oneOf
  • ad-hoc JSON objectsc.JSON(fiber.Map{...}) / map[string]any{...} are expanded into an object with concrete properties; value types are inferred from the expressions, and nested literals and $refs are supported (e.g. {"message": string, "data": SomeStruct})

Types → JSON Schema

  • structs → reusable components ($ref), honoring json: tags, omitempty (drives required), and embedded/promoted fields
  • pointers → nullable (oneOf + null in 3.1, nullable: true in 3.0)
  • slices/arrays → array, maps → additionalProperties, []bytestring/byte
  • named types backed by a group of constants → enum
  • well-known types: time.Timedate-time, time.Duration, encoding/json.RawMessage, uuid.UUID, MongoDB primitive.ObjectID/DateTime, interface{}/any → free-form, fiber.Map → object
  • cross-package name collisions are disambiguated by package name (e.g. models.User vs. dto.User)

Example

A handler like this:

func (h *UserHandler) Create(c fiber.Ctx) error {
    var req CreateUserRequest
    if err := c.Bind().Body(&req); err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid body"})
    }
    user := h.svc.Create(req)
    return c.Status(fiber.StatusCreated).JSON(user)
}

…with the route app.Group("/api/v1").Group("/users").Post("/", h.Create) produces:

/api/v1/users:
  post:
    tags: [users]
    operationId: post_api_v1_users
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CreateUserRequest'
    responses:
      "201":
        description: Created
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      "400":
        description: Bad Request
        content:
          application/json:
            schema:
              type: object
              properties:
                error: { type: string }
              required: [error]

Two ready-to-run example projects (Fiber v2 and v3) live under examples/.

How it works

cmd/fibgen          CLI entrypoint
internal/analyzer   load packages, find routes, resolve group prefixes, analyze handler bodies
internal/schema     go/types -> version-neutral JSON Schema (+ component registry)
internal/model      framework-neutral API model (routes, params, responses)
internal/openapi    render the model to OpenAPI 3.0/3.1, serialize to YAML/JSON
internal/oapi       insertion-ordered map for deterministic, diff-friendly output
examples/v2, v3     example Fiber projects used by the test suite

Pipeline: analyzer.Analyzemodel.APIopenapi.Builder.Buildoapi.OMopenapi.Marshal.

Building

./build.sh            # current platform -> ./bin/fibgen
./build.sh all        # cross-compile linux/macos/windows (amd64 + arm64)
./build.sh install    # go install into $GOBIN / $GOPATH/bin

Windows: use build.bat with the same subcommands.

Limitations

Static analysis does not execute code, so there are honest boundaries:

  • Dynamic call targets. Helpers and handler factories are followed when their target can be resolved statically. Calls through interfaces, dependency-injection containers, or dynamically selected function values may retain only the information visible at the call site.
  • Dynamic paths. A path built from a non-constant string is skipped (with a note: on stderr).
  • Handlers behind DI/registries. If a handler cannot be resolved statically to a function (passed through an interface/container), its body is not analyzed and the route appears with a default 200 response.
  • Generics in response types are handled in a limited way.
  • Descriptions / summaries are not generated — there is no source for them without comments. This is a deliberate trade-off for zero-annotation operation.

Testing

go test ./...

The internal/openapi test analyzes the bundled examples/v2 and examples/v3 projects and validates the generated documents with kin-openapi.

Contributing

Issues and pull requests are welcome. Good first areas: interprocedural analysis (following response helpers), more binding patterns, and richer well-known type mappings.

License

MIT

About

OpenAPI for Go Fiber via static analysis, zero annotations

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages