OPEN SWAG GO

Changelog

v1.3.0

A spec-correctness release. Fixes the five bugs that made the generated openapi.json wrong or unusable for code generators (router-style paths, dropped embedded structs, silently overwritten duplicates, missing null for pointers, missing operationId), maps go-playground/validator rules onto JSON Schema constraints, and hardens the docs UI. Named structs are now emitted as reusable components.schemas entries, and packages that were never used by the runtime have been removed.

go get github.com/gopackx/open-swag-go@v1.3.0

Breaking changes

  • Dead packages removed. The following were never wired into the runtime: nothing in the handler, the spec builder or the docs page called them, so their settings had no effect. Code that imports them no longer compiles.
    • pkg/auth (scheme constructors, playground config, credential persistence). Use openswag.BearerAuth, APIKeyAuth, APIKeyQueryAuth, BasicAuth, CookieAuth in Config.Auth.Schemes and the Security* constants from the root package.
    • pkg/tryit (console config, environments, request history) and pkg/tryit/snippets (code snippet generators). The try-it console, request history, environments and code snippets in the docs UI are Scalar features and need no configuration.
    • pkg/ui/themes.go: Theme, ThemeColors, ThemeFonts, PredefinedThemes, GetTheme, Theme.ToCSS. UIConfig.Theme is passed to Scalar as-is.
    • pkg/examples/templates.go and pkg/examples/faker.go: Template, TemplateRegistry, NewTemplateRegistry, Faker, NewFaker, and the examples.Config.UseFaker field. examples.New, Generate, GenerateJSON and DefaultTypeExamples remain.
    • pkg/schema/validator.go (Validator, NewValidator, ValidationError) and pkg/schema/types.go (TypeMappings, FormatMappings, GetTypeMapping).
  • Deprecated UIConfig fields. SidebarSearch, TagGrouping and CollapsibleSchemas are kept for compatibility but marked Deprecated: has no effect. They were never passed to Scalar, which always shows the sidebar search, groups operations by tag and renders collapsible model sections. AuthConfig.PersistCredentials is likewise not read anywhere and has no runtime effect.

Behaviour changes in generated spec

  • Named structs are $ref components. Every named struct used in a request or response body (directly, or nested via a field, slice element or map value) is emitted once under components.schemas and referenced with {"$ref": "#/components/schemas/<Name>"}, so code generators produce named types (components['schemas']['User'] with openapi-typescript). Anonymous structs, embedded structs (still flattened into the parent) and all parameters stay inline. Recursive structs get a real self-$ref instead of the Recursive reference to ... placeholder.

    • Names are the Go type name. When two different types share a name, the first registered keeps it (endpoint order; request body, then responses by ascending status code, then field order) and the next gets its package name as a prefix (model.User → modelUser), then a numeric suffix (modelUser2). Generic names are sanitised to [A-Za-z0-9_.-]: Page[github.com/x/dto.User] → Page_dto.User.
    • Nullable references. A pointer to a named struct is {"oneOf": [{"$ref": "#/components/schemas/Address"}, {"type": "null"}]}. A field description is kept as a sibling of the $ref (on the outer object for a nullable one); other tags on a struct-typed field (example, enum, format, validate bounds) are dropped.
    • Config.InlineSchemas: true restores the previous output. See Schema Components.
    "requestBody": {
      "content": {
        "application/json": { "schema": { "$ref": "#/components/schemas/CreateUserRequest" } }
      }
    }
  • Nullable fields use OpenAPI 3.1 type arrays. Pointer fields (Name *string) now produce "type": ["string", "null"]. Previously they were emitted as a plain string. The 3.0 nullable keyword is never written. A top-level pointer passed to RequestBody.Schema or a response (&User{}) is not nullable, and query/path parameters treat a pointer as optional rather than nullable.

  • Every operation has an operationId. When Endpoint.OperationID is empty one is derived from the method and path in lowerCamelCase: GET /users/{id} becomes getUsersById, POST /users becomes postUsers, GET / becomes getRoot.

  • Router-style paths are normalised. /users/:id, /files/*path and chi regex segments such as /users/{id:[0-9]+} are written to the spec as /users/{id}, /files/{path} and /users/{id}.

  • Embedded structs with an unexported type are promoted. type base struct{...} embedded as base used to vanish from the schema; its exported fields are now flattened into the parent like encoding/json does. A field declared on the outer struct shadows a promoted one with the same name, and a json tag on the embedded field (base `json:"base"` ) makes it a nested property instead.

  • required_if and other conditional rules no longer mark a field required. Only a bare required rule (in the swagger, validate or binding tag) does.

  • HEAD, OPTIONS and TRACE are supported. They used to produce an empty path item ("/health": {}).

New public API

  • func (d *Docs) Validate() error reports duplicate method+path pairs, unsupported HTTP methods and duplicate operationIds in one joined error. Call it once after AddAll.
  • Endpoint.OperationID string overrides the generated operationId.
  • UIConfig.ScalarVersion string pins the @scalar/api-reference version loaded from the CDN. Empty uses ui.DefaultScalarVersion ("1.75.0").
  • UIConfig.SpecCORSOrigin string controls the Access-Control-Allow-Origin header on the spec endpoint: "" keeps *, "-" omits the header, any other value is sent as-is.
  • enum:"a,b,c" struct tag sets explicit enum values, converted to the field type. It takes precedence over validate:"oneof=...".
  • Validator rule mapping. validate and binding tags now produce constraints: oneof becomes enum, min/max/gte/lte/gt/lt/len become minLength/maxLength, minimum/maximum or minItems/maxItems depending on the field type, email/uuid/url/ipv4/ipv6/hostname set format, and dive applies the following rules to slice items. See Schema Generation.
  • Config.InlineSchemas bool (default false) disables schema components: no components.schemas, every struct inlined at each use, recursive back-edges become {type: object, description: "Recursive reference to ..."}.
  • Schema registry in pkg/schema: Registry (Names(), Schema(name), Len(), NameOf(reflect.Type)), NewRegistry(), FromTypeWithRegistry(v, reg), FromReflectTypeWithRegistry(t, reg) and the constant RefPrefix = "#/components/schemas/". FromType and FromReflectType are unchanged and still inline everything. See Schema Package.
  • Query and path parameter structs use the body tag rules. swagger:"required", description, format, example, enum and validator rules now work on Endpoint.QueryParams / Endpoint.PathParams fields too.

Fixed

  • fix(openapi): A second endpoint with the same method and path no longer silently replaces the first without any signal. BuildSpec still keeps the last one, but Validate reports it.
  • fix(openapi): Unsupported HTTP methods no longer produce an empty path item; they are skipped and reported by Validate.
  • fix(openapi): Parameter.Example on an explicitly declared Endpoint.Parameters entry is now written to the spec; previously only struct-derived parameters could carry an example.
  • fix(ui): The docs HTML is rendered with html/template, so Info.Title and the spec URL are escaped. CustomCSS is still inserted verbatim and must come from trusted configuration.
  • fix(ui): The Scalar CDN script is pinned to a version instead of tracking the latest upstream release.
  • fix(handler): DocsAuth with Enabled: true but no APIKey and no Username+Password now answers every request with HTTP 500 DocsAuth enabled but no credentials configured instead of a 401 that looked like a wrong password.
  • fix(versioning): The version differ understands 3.1 type arrays. Adding null to a field's type is not reported as a type change.
  • fix(versioning): The differ resolves #/components/schemas/<Name> references (following up to 8 chained refs) when comparing request-body required fields and property types, and treats a nullable oneOf [$ref, null] like the referenced type. Moving a struct into components, or making it nullable, is not reported as a type change. A reference that cannot be resolved is compared as $ref:<ref>.
  • fix(schema): Recursive structs are described completely through a self-$ref instead of being cut off at the back-edge.
  • docs: README and the bundled Claude Skill corrected (no Handler field on Endpoint; the snippet package import shown in the README and its PHP generator did not exist). The try-it console, auth playground and code snippets in the docs UI are Scalar features.
  • ci: CI now runs on master with gofmt, go vet and golangci-lint.

Migrating from v1.2.0

  • Regenerate your TypeScript types. Pointer fields now come out as string | null (or number | null, …) instead of string, so frontend code may need null checks. Named structs are now named types (components['schemas']['User'] with openapi-typescript, named interfaces with orval) instead of anonymous inline objects.
  • Remove imports of the deleted packages (pkg/auth, pkg/tryit, pkg/tryit/snippets, and the removed parts of pkg/ui, pkg/examples and pkg/schema listed under Breaking changes). Replace auth.BearerAuth(...) and friends with openswag.BearerAuth(name) etc. in Config.Auth.Schemes; drop console, snippet and playground configuration.
  • Need the old inline spec for now? Set InlineSchemas: true on Config to keep the pre-v1.3.0 output while you migrate generated clients.
  • Move tags off struct-typed fields. example, enum, format and validate bounds on a field whose type is a named struct are dropped next to the $ref; put them on the struct's own fields.
  • Check generated names. orval names functions and hooks after operationId, and openapi-typescript keys its operations interface by it. Every operation now has one, so names your generator previously invented may change; set Endpoint.OperationID where you need a specific name.
  • Call docs.Validate() after AddAll and treat an error as fatal. If it reports duplicates, one of your endpoints was silently missing from the spec before.
  • Review fields relying on required_if (or required_with, required_without, …). They are no longer listed in required; add swagger:"required" if they really are always required.

See the Migration Guide for examples.

v1.2.0

A bug-fix + DX release. Closes the four bugs that produced wrong specs at runtime (self-referential structs, ignored ContentType, silent bearer fallback, dormant type-change detector) and finally ships the public API the README has been documenting all along.

go get github.com/gopackx/open-swag-go@v1.2.0

Breaking change

  • The Response struct is renamed to ResponseSpec so openswag.Response(desc, schema) can be the constructor the README documents. Field-keyed literals inside openswag.Responses{ ... } keep compiling unchanged — only bare openswag.Response{...} literals need to migrate (use openswag.Response("desc", T{}) or openswag.ResponseSpec{...}).

Fixed

  • fix(schema): Self-referential structs (e.g. type Category struct { Children []Category }) no longer cause a stack overflow during spec generation. fromReflectType now threads a visiting-type set; back-edges return a bounded object schema with a description note.
  • fix(openapi): RequestBody.ContentType is now honored end-to-end. multipart/form-data and application/x-www-form-urlencoded bodies appear in the spec under the correct media type instead of being silently rewritten to application/json. Added pkg/spec.RequestBody.WithContent(mediaType, schema) to back the new behavior.
  • fix(openapi): Custom security scheme names referenced from Endpoint.Security are no longer silently coerced into http-bearer. Unknown names are now omitted from components.securitySchemes so typos surface immediately. Register custom schemes explicitly via the new Config.Auth.Schemes field.
  • fix(versioning): compareOperations now produces entries for BreakingTypeChanged. Changes to a request-body field's JSON type/format and changes to a parameter's schema type are flagged as breaking, with migration hints. Also fixed a latent index-out-of-range bug in getMigrationGuide (short descriptions could panic the migration formatter).

New public API

The README has documented these helpers for several versions, but the package never exposed them — Quick Start examples could not compile. They exist now:

  • Request body builders: Body(schema), BodyWithDesc(desc, schema), FormBody(schema), FormURLEncodedBody(schema) — all return *RequestBody ready to drop into Endpoint.RequestBody.
  • Response constructor: Response(desc, schema...) returns a ResponseSpec. Pass the schema as the second argument or omit it for empty responses (e.g. 204 No Content). The type alias Responses = map[int]ResponseSpec exists for the decorator-style map literal.
  • Parameter helpers: PathParam, QueryParam, RequiredQueryParam, HeaderParam, CookieParam — all return a Parameter ready for Endpoint.Parameters.
  • Auth scheme helpers: BearerAuth(name), APIKeyAuth(name, header), APIKeyQueryAuth(name, param), BasicAuth(name), CookieAuth(name, cookieName) — all return an AuthScheme for registration via Config.Auth.Schemes.
  • Config surface: Config.Auth AuthConfig (with PersistCredentials and Schemes fields) plus the AuthScheme struct. The new SecurityCookieAuth constant joins the existing Security* family for the predefined-name shortcut.

Migrating from v1.1.1

  • Replace bare openswag.Response{...} literals with openswag.Response("desc", Schema{}) or openswag.ResponseSpec{...}. Literals inside openswag.Responses{ ... } (or the equivalent typed map) continue to compile via Go's composite-literal type inference.

  • If you were referencing custom security scheme names from Endpoint.Security and relying on them magically becoming http-bearer, register them explicitly:

    Auth: openswag.AuthConfig{
        Schemes: []openswag.AuthScheme{
            openswag.BearerAuth(openswag.SecurityBearerAuth),
            openswag.APIKeyAuth("apiKey", "X-API-Key"),
        },
    },
  • File-upload endpoints that previously had a ContentType: "multipart/form-data" set on RequestBody will now produce a different spec than before — review your generated openapi.json and update downstream clients/code generators accordingly.

v1.1.1

Cleaner specs out of the box. Examples are now opt-in: you only see them where you ask for them, and null is supported as a first-class example value. Fully backwards-compatible — no API signatures changed.

go get github.com/gopackx/open-swag-go@v1.1.1

Behavior change worth flagging

  • Examples are now opt-in. Auto-generated example values for primitive fields have been removed. Previously every primitive field got a placeholder ("string", 0, false, …) in the spec even without an example tag, which produced noisy Scalar UI. Now examples appear only where you set example:"..." on the field.

What's new

  • example:"null" literal — Setting example:"null" on any field type now produces actual JSON null in the spec (previously only worked for slices/maps). Useful for documenting nullable fields.

Fixed

  • Stray "example": null entries no longer leak into request body schemas when no example is provided (typed-nil interface bug).

Migrating from v1.1.0

If you relied on the old auto-generated placeholders to populate the Scalar UI, add explicit example:"..." tags to the fields you want shown — see the Migration Guide for details.

v1.1.0

All 12 fixes are backwards-compatible — no public API signatures changed, only additive struct fields and behavior corrections.

go get github.com/gopackx/open-swag-go@v1.1.0

Critical Fixes

  • fix(spec): Fixed port-to-string conversion in CommonServers.Localhost() and LocalhostServer() — replaced broken string(rune(port)) with strconv.Itoa(port). Also fixed the same pattern in intToString() in openapi.go.
  • fix(schema): Example tag values are now coerced to the correct type via ConvertExampleToType(). example:"42" on an int64 field now produces the integer 42, not the string "42". Applied in pkg/schema/tags.go, openapi.go, and pkg/examples/generator.go.
  • fix(schema): $ref pointers are no longer silently dropped during schema conversion — added Ref: s.Ref mapping in convertSchema().

High Severity Fixes

  • fix(schema): Embedded (anonymous) struct fields are now detected via field.Anonymous and their properties are promoted into the parent schema.
  • fix(schema): map[K]V types now correctly generate {"type":"object","additionalProperties":{...}}. Added AdditionalProperties field to schema.Schema and conversion in convertSchema().
  • fix(schema): interface{}/any fields now produce an empty schema {} (accepts any type) instead of {"type":"object"}. Validator updated to accept empty schemas.

Medium Severity Fixes

  • fix(schema): Fields with json:",omitempty" are no longer marked as required even if validate:"required" is present.
  • feat(schema): Added Nullable, ReadOnly, WriteOnly, Deprecated, MinItems, MaxItems, UniqueItems, AllOf, OneOf, AnyOf fields to schema.Schema and full conversion support in convertSchema().
  • fix(schema): Added special handling for time.Duration → {format:"duration"}, []byte → {format:"byte"}, uuid.UUID → {format:"uuid"}.
  • fix(schema): json:",omitempty" (empty name part) now correctly falls back to the Go field name.

Low Severity Fixes

  • fix(openapi): buildParamsFromStruct now prefers location-specific tags (query tag for query params, path tag for path params) before falling back to generic tags.
  • feat(openapi): Request body schemas now include an auto-generated example field built from struct field tags and type defaults.

v1.0.0

Initial release of open-swag-go.

  • 5 framework adapters: Chi, Gin, Echo, Fiber, net/http
  • Authentication playground with Bearer, Basic, API Key, Cookie, and OAuth2 support
  • Try-it console with environment management and request history
  • Auto-generated code snippets in curl, JavaScript, Go, and Python
  • Version diffing with breaking change detection and migration guides
  • Schema generation from Go structs using standard tags
  • Theming with Scalar UI (purple, blue, green, light themes + dark mode)
  • Docs page authentication with basic auth or API key
  • Smart example generation from struct field names and tags