Advanced Features
Generic Response Types
oaswrap/spec fully supports Go generics for response wrapping patterns:
type APIResponse[T any] struct {
Success bool `json:"success"`
Data T `json:"data,omitempty"`
Error string `json:"error,omitempty"`
Timestamp string `json:"timestamp"`
}
type PaginatedResponse[T any] struct {
Items T `json:"items"`
Total int `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
r.Get("/users",
option.Response(200, new(PaginatedResponse[[]User])),
)
r.Get("/users/{id}",
option.Response(200, new(APIResponse[User])),
option.Response(404, new(APIResponse[any])),
)
Spec Validation
Validate the generated spec before writing it:
if err := r.Validate(); err != nil {
log.Fatalf("Invalid OpenAPI spec: %v", err)
}
Writing Specs
Multiple output formats and destinations:
// Write YAML to file
if err := r.WriteSchemaTo("openapi.yaml"); err != nil {
log.Fatal(err)
}
// Write JSON to file
if err := r.WriteSchemaTo("openapi.json"); err != nil {
log.Fatal(err)
}
// Get raw YAML bytes
yamlBytes, err := r.MarshalYAML()
// Get raw JSON bytes
jsonBytes, err := r.MarshalJSON()
// Generate with format selection
bytes, err := r.GenerateSchema("yaml")
bytes, err := r.GenerateSchema("json")
OpenAPI 3.1 Support
Switch to OpenAPI 3.1 by setting the version:
r := spec.NewRouter(
option.WithOpenAPIVersion("3.1.0"),
option.WithTitle("My API"),
option.WithVersion("1.0.0"),
)
Rich Schema Documentation
Struct tags map directly to JSON Schema constraints:
type Product struct {
ID string `json:"id" format:"uuid" description:"Unique product identifier"`
Name string `json:"name" required:"true" minLength:"1" maxLength:"200"`
Price float64 `json:"price" required:"true" minimum:"0" exclusiveMinimum:"true"`
Currency string `json:"currency" enum:"USD,EUR,GBP" default:"USD"`
Tags []string `json:"tags,omitempty" maxItems:"10" uniqueItems:"true"`
Description string `json:"description,omitempty" maxLength:"2000"`
CreatedAt string `json:"created_at" format:"date-time" readOnly:"true"`
}
For the complete list of supported tags, see:
Embedding Spec in Binary
Combine with spec-ui to serve the spec from an embedded file:
import (
"embed"
specui "github.com/oaswrap/spec-ui"
"github.com/oaswrap/spec-ui/swaggerui"
)
//go:embed openapi.yaml
var specFS embed.FS
handler := specui.NewHandler(
specui.WithSpecEmbedFS("openapi.yaml", specFS),
swaggerui.WithUI(),
)
Runtime Spec Generation
Use WithSpecGenerator to generate the spec at request time:
type myGenerator struct {
router spec.Generator
}
func (g *myGenerator) MarshalYAML() ([]byte, error) {
return g.router.MarshalYAML()
}
handler := specui.NewHandler(
specui.WithSpecGenerator(&myGenerator{router: r}),
swaggerui.WithUI(),
)