OPEN SWAG GO
Guides

Migrating from v1.2.0 to v1.3.0

Existing endpoint definitions and Config literals keep compiling, but the generated openapi.json is different in ways that matter to code generators, and several packages that were never used by the runtime have been removed. Update by running:

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

See the Changelog for the full list.

What Changed

Named structs are schema components. Every named struct used in a request or response body (directly, or nested through a field, slice element or map value) is emitted once under components.schemas and referenced with $ref:

type Address struct {
    City string `json:"city"`
}
 
type User struct {
    Name    string   `json:"name"`
    Address Address  `json:"address" description:"Home address"`
    Billing *Address `json:"billing"`
}
 
// RequestBody: &openswag.RequestBody{Schema: User{}}
// Before: every struct inlined at each use (the InlineSchemas: true output;
// v1.2.0 also lacked the "null" in billing's type)
"schema": {
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "address": {
      "type": "object",
      "description": "Home address",
      "properties": { "city": { "type": "string" } }
    },
    "billing": {
      "type": ["object", "null"],
      "properties": { "city": { "type": "string" } }
    }
  }
}
 
// v1.3.0+
"schema": { "$ref": "#/components/schemas/User" }
 
"components": {
  "schemas": {
    "User": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "address": { "$ref": "#/components/schemas/Address", "description": "Home address" },
        "billing": { "oneOf": [{ "$ref": "#/components/schemas/Address" }, { "type": "null" }] }
      }
    },
    "Address": {
      "type": "object",
      "properties": { "city": { "type": "string" } }
    }
  }
}

Code generators now produce named types (components['schemas']['User'] with openapi-typescript, a User interface with orval). Recursive structs reference themselves with $ref instead of ending in {type: object, description: "Recursive reference to ..."}. Anonymous structs, embedded structs (still flattened) and all parameters stay inline. Components are named after the Go type; a second, different type with the same name gets its package name as a prefix (modelUser). Field tags other than description on a struct-typed field (example, enum, format, validate bounds) are dropped next to a $ref; move them to the struct's own fields. To keep the old output while you migrate, set InlineSchemas:

docs := openswag.New(openswag.Config{
    Info:          openswag.Info{Title: "My API", Version: "1.0.0"},
    InlineSchemas: true, // v1.3.0+: no components.schemas, everything inlined
})

See Schema Components for the naming rules.

Pointer fields are nullable (OpenAPI 3.1 style). A pointer field now produces a type array instead of a plain type:

type User struct {
    Nickname *string `json:"nickname"`
}
// Before v1.3.0
"nickname": { "type": "string" }
 
// v1.3.0+
"nickname": { "type": ["string", "null"] }

openapi-typescript therefore generates nickname: string | null. A top-level pointer passed as a body or response schema (&User{}) is not nullable, and query/path parameter structs treat a pointer as optional, not nullable.

Every operation has an operationId. It defaults to the method plus path in lowerCamelCase (GET /users/{id} → getUsersById). Set Endpoint.OperationID to pick your own:

openswag.Endpoint{
    Method:      "GET",
    Path:        "/users/{id}",
    OperationID: "getUser", // v1.3.0+
}

Router-style paths are normalised. /users/:id, /files/*path and /users/{id:[0-9]+} are written as /users/{id}, /files/{path} and /users/{id}.

Embedded unexported structs are promoted. Embedding a lowercase type such as base used to drop its fields from the schema; they are now flattened into the parent, following encoding/json.

Conditional validator rules no longer mean required. validate:"required_if=...", required_with, required_without and similar rules do not add the field to required. Only a bare required does.

Duplicate endpoints and unsupported methods are reportable. Add still never fails and BuildSpec still keeps the last duplicate, but the new Docs.Validate() reports duplicate method+path pairs, unsupported HTTP methods and duplicate operationIds.

Removed packages

These packages 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.

RemovedUse instead
pkg/auth (scheme constructors, playground config, credential store)The root package: openswag.BearerAuth, APIKeyAuth, APIKeyQueryAuth, BasicAuth, CookieAuth in Config.Auth.Schemes, plus the Security* constants. The auth playground itself is Scalar's; see Auth Playground
pkg/tryit (console config, environments, request history)Nothing to configure: the try-it console is a Scalar feature. Shape it through the spec (Config.Servers, endpoints); see Try-It Console
pkg/tryit/snippetsNothing to configure: Scalar generates the code snippets; see Code Snippets
pkg/ui/themes.go (Theme, ThemeColors, ThemeFonts, the predefined theme list and its lookup and CSS helpers)UIConfig.Theme (passed to Scalar as-is) and UIConfig.CustomCSS; see Theming
pkg/examples/templates.go, pkg/examples/faker.go, examples.Config.UseFakerexamples.New, Generate, GenerateJSON and DefaultTypeExamples remain; see Example Generator
pkg/schema/validator.go (Validator, NewValidator, ValidationError)Validate values with your own validator (e.g. go-playground/validator)
pkg/schema/types.go (TypeMappings, FormatMappings, GetTypeMapping)schema.FromType / FromReflectType apply the type mapping directly
// Before
import "github.com/gopackx/open-swag-go/pkg/auth"
 
bearer := auth.BearerAuth("JWT access token")
 
// v1.3.0+
docs := openswag.New(openswag.Config{
    Info: openswag.Info{Title: "My API", Version: "1.0.0"},
    Auth: openswag.AuthConfig{
        Schemes: []openswag.AuthScheme{openswag.BearerAuth(openswag.SecurityBearerAuth)},
    },
})

UIConfig.SidebarSearch, TagGrouping and CollapsibleSchemas are still there but marked Deprecated: has no effect; they were never passed to Scalar. You can delete them from your configuration. AuthConfig.PersistCredentials likewise has no runtime effect.

Migration Checklist

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

  • Add docs.Validate() after AddAll and treat an error as fatal:

    docs.AddAll(handlers.Endpoints...)
    if err := docs.Validate(); err != nil {
        log.Fatal(err)
    }
  • Regenerate your TypeScript types: pointer fields now come out as T | null, so add null checks where the compiler asks for them

  • Switch hand-written type aliases to the named types (components['schemas']['User']) now that named structs are $ref components; set InlineSchemas: true temporarily if you need the old inline output

  • Move example, enum, format and validate tags off struct-typed fields onto the struct's own fields (they are dropped next to a $ref)

  • If two different structs share a name, check the generated component names (User, modelUser) or rename one of the types

  • Remove imports of pkg/auth, pkg/tryit, pkg/tryit/snippets, the faker and template helpers in pkg/examples, and the validator and type-mapping helpers in pkg/schema; use openswag.BearerAuth and friends for security schemes

  • Drop SidebarSearch, TagGrouping and CollapsibleSchemas from UIConfig (deprecated, no effect)

  • Check generated names (orval functions and hooks, openapi-typescript operations keys): they now follow operationId and may change; set Endpoint.OperationID where you need a stable name

  • Review fields that relied on required_if / required_with / required_without being listed as required; add swagger:"required" if they always are

  • If DocsAuth.Enabled is true, make sure APIKey or both Username and Password are set; otherwise the docs now return HTTP 500


Migrating from v1.0.x to v1.1.1

v1.1.0 and v1.1.1 are both fully backwards-compatible — no public API signatures changed, and existing endpoint definitions continue to compile. v1.1.0 ships 12 schema-generation fixes; v1.1.1 makes example values opt-in for cleaner specs. Update by running:

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

What Changed

Schema Generation Fixes

Embedded struct promotion — Embedded (anonymous) struct fields now have their properties promoted into the parent schema, matching Go's field promotion behavior.

// Before v1.1.0: Embedded fields were ignored
// After v1.1.0: Embedded fields are promoted
type Timestamps struct {
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}
 
type User struct {
    Timestamps // Now correctly promoted into User's schema
    ID   int64  `json:"id"`
}

Map types generate additionalProperties — map[K]V types now correctly produce {"type":"object","additionalProperties":{...}}.

interface/any produces empty schema — Fields typed as interface{} or any now generate an empty schema {} (accepts any value) instead of {"type":"object"}.

omitempty overrides required — Fields with json:",omitempty" are no longer marked as required, even if validate:"required" is set.

New schema fields — ReadOnly, WriteOnly, Deprecated, MinItems, MaxItems, UniqueItems, AllOf, OneOf, AnyOf, and AdditionalProperties are now supported on the Schema struct.

Special type handling — time.Duration → {format:"duration"}, []byte → {format:"byte"}, uuid.UUID → {format:"uuid"}.

$ref preservation — $ref pointers are no longer silently dropped during schema conversion.

Example Generation Fixes

Type-coerced examples — Example tag values are now coerced to the correct type. example:"42" on an int64 field produces the integer 42 in the spec, not the string "42".

Request body auto-examples — Request body schemas now automatically include a generated example field built from struct tags and type defaults.

Parameter Handling Fixes

Location-specific tags preferred — Parameter structs passed as Endpoint.QueryParams / Endpoint.PathParams now prefer query tags for query params and path tags for path params before falling back to json tags.

Server Configuration Fixes

Port conversion fix — CommonServers.Localhost() and LocalhostServer() now correctly convert port numbers to strings (previously used invalid string(rune(port)) conversion). If you used openswag.LocalhostServer(port) or CommonServers.Localhost(port) on v1.0.0, the URL was silently broken — upgrading is strongly recommended.

What Changed in v1.1.1

Examples are now opt-in. v1.1.0 auto-generated placeholder example values for every primitive field ("string", 0, false, …) even when no example tag was set. v1.1.1 removes that behavior — example values appear only where you set example:"...". The result is a cleaner Scalar UI without placeholder noise.

If your spec was relying on those placeholders to populate the rendered docs, add explicit example:"..." tags to the fields you want shown:

// Before (v1.1.0 would auto-fill these in the spec)
type CreateUserRequest struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}
 
// After (v1.1.1 — be explicit about which examples you want)
type CreateUserRequest struct {
    Name  string `json:"name"  example:"Jane Doe"`
    Email string `json:"email" example:"jane@example.com"`
}

example:"null" literal — Setting example:"null" on any field type now produces a real JSON null in the spec (previously this only worked for slices and maps). Use it to document nullable fields.

Typed-nil example bug fixed — Stray "example": null entries no longer leak into request body schemas when no example is provided.

Migration Checklist

  • Run go get github.com/gopackx/open-swag-go@v1.1.1
  • Review any interface{}/any fields — they now produce empty schemas instead of {"type":"object"} (v1.1.0)
  • Review fields with both omitempty and validate:"required" — omitempty now takes precedence (v1.1.0)
  • Verify embedded struct schemas are promoted correctly (v1.1.0)
  • Check that example values in your spec now have correct types (integers, floats, booleans) (v1.1.0)
  • Add explicit example:"..." tags to any fields where you previously relied on auto-generated placeholders (v1.1.1)
  • If you used openswag.LocalhostServer(port) on v1.0.0, regenerate your spec — the URL output is now correct
  • Run your test suite to confirm no regressions

Migrating from v0.x to v1.0

Config Structure

The Config struct was restructured to group related settings.

Before

docs := openswag.New(openswag.Config{
    Info: openswag.Info{
    	Title:       "My API",
    	Version:     "1.0.0",
    },
    BasePath:    "/api",
    DocsPath:    "/docs",
    Theme:       "purple",
    DarkMode:    true,
})

After

docs := openswag.New(openswag.Config{
    Info: openswag.Info{
        Title:   "My API",
        Version: "1.0.0",
    },
    UI: openswag.UIConfig{
        Theme:    "purple",
        DarkMode: true,
    },
})
 
// The mount path is passed to Mount, not configured on Config:
docs.Mount(mux, "/docs")

Endpoint Definitions

Endpoints now use struct-based parameter definitions instead of inline strings.

Before

docs.AddEndpoint(openswag.Endpoint{
    Method:  "GET",
    Path:    "/users/{id}",
    Summary: "Get user",
    Params: map[string]string{
        "id": "string",
    },
    Response: `{"id": "string", "name": "string"}`,
})

After

type GetUserParams struct {
    ID string `param:"id" description:"User ID"`
}
 
type User struct {
    ID   string `json:"id" example:"usr_123"`
    Name string `json:"name" example:"Jane Doe"`
}
 
docs.Add(openswag.Endpoint{
    Method:     "GET",
    Path:       "/users/{id}",
    Summary:    "Get user",
    PathParams: GetUserParams{},
    Responses: openswag.Responses{
        200: {Description: "User found", Schema: User{}},
    },
})

Authentication Schemes

Auth schemes moved from a single inline config to named schemes referenced per endpoint. The snippet below uses the current API (v1.3.0+, root-package helpers).

Before

docs := openswag.New(openswag.Config{
    Auth: openswag.Auth{
        Type:   "bearer",
        Scheme: "JWT",
    },
})

After

// Register the scheme definition on Config.Auth:
docs := openswag.New(openswag.Config{
    Info: openswag.Info{Title: "My API", Version: "1.0.0"},
    Auth: openswag.AuthConfig{
        Schemes: []openswag.AuthScheme{openswag.BearerAuth(openswag.SecurityBearerAuth)},
    },
})
 
// Reference the scheme by name on each protected endpoint:
docs.Add(openswag.Endpoint{
    Method:   "GET",
    Path:     "/users/me",
    Security: []string{openswag.SecurityBearerAuth},
    // ...
})

Framework Adapter Mounting

Adapter mounting functions were unified across all frameworks.

Before

// Chi
r.Handle("/docs/*", docs.Handler())
 
// Gin
r.Any("/docs/*any", gin.WrapH(docs.Handler()))

After

// Chi
import chiadapter "github.com/gopackx/open-swag-go/adapters/chi"
chiadapter.Mount(r, docs, "/docs")
 
// Gin
import ginadapter "github.com/gopackx/open-swag-go/adapters/gin"
ginadapter.Mount(r, docs, "/docs")

Schema Generation Tags

The swagger struct tag syntax was updated for clarity.

Before

type Product struct {
    ID    int     `json:"id" swagger:"integer,required"`
    Price float64 `json:"price" swagger:"number,format=double"`
}

After

type Product struct {
    ID    int     `json:"id" swagger:"required" format:"int64"`
    Price float64 `json:"price" format:"double" example:"29.99"`
}

Try-It Console

The console options were removed from Config. The try-it console is provided by the Scalar UI and needs no configuration (see Try-It Console).

Before

docs := openswag.New(openswag.Config{
    Console: true,
    ConsoleTheme: "dark",
})

After

// No console settings: the base URLs the console calls come from Config.Servers.
docs := openswag.New(openswag.Config{
    Info: openswag.Info{
        Title:   "My API",
        Version: "1.0.0",
    },
    Servers: []openswag.Server{{URL: "http://localhost:8080"}},
})

Migration Checklist

  • Update Config to use nested Info and UIConfig structs
  • Convert inline parameter definitions to struct-based QueryParams / PathParams
  • Move auth configuration to named schemes in Config.Auth.Schemes referenced from Endpoint.Security
  • Update framework adapter mounting to use adapter-specific Mount() functions
  • Update struct tags to new swagger tag syntax
  • Remove console configuration (the Scalar UI provides the try-it console)
  • Run go vet and fix any compilation errors
  • Regenerate your OpenAPI spec and verify output