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.0See 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.
| Removed | Use 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/snippets | Nothing 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.UseFaker | examples.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()afterAddAlland 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$refcomponents; setInlineSchemas: truetemporarily if you need the old inline output -
Move
example,enum,formatandvalidatetags 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 inpkg/examples, and the validator and type-mapping helpers inpkg/schema; useopenswag.BearerAuthand friends for security schemes -
Drop
SidebarSearch,TagGroupingandCollapsibleSchemasfromUIConfig(deprecated, no effect) -
Check generated names (orval functions and hooks, openapi-typescript
operationskeys): they now followoperationIdand may change; setEndpoint.OperationIDwhere you need a stable name -
Review fields that relied on
required_if/required_with/required_withoutbeing listed as required; addswagger:"required"if they always are -
If
DocsAuth.Enabledis true, make sureAPIKeyor bothUsernameandPasswordare 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.1What 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{}/anyfields — they now produce empty schemas instead of{"type":"object"}(v1.1.0) - Review fields with both
omitemptyandvalidate:"required"—omitemptynow 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
Configto use nestedInfoandUIConfigstructs - Convert inline parameter definitions to struct-based
QueryParams/PathParams - Move auth configuration to named schemes in
Config.Auth.Schemesreferenced fromEndpoint.Security - Update framework adapter mounting to use adapter-specific
Mount()functions - Update struct tags to new
swaggertag syntax - Remove console configuration (the Scalar UI provides the try-it console)
- Run
go vetand fix any compilation errors - Regenerate your OpenAPI spec and verify output