Documentation
¶
Overview ¶
Package builder provides programmatic construction of OpenAPI Specification documents.
The builder package enables users to construct OAS documents in Go using a fluent API with automatic reflection-based schema generation. Go types are passed directly to the API, and the builder automatically generates OpenAPI-compatible JSON schemas.
Supported Versions ¶
The builder supports both OAS 2.0 (Swagger) and OAS 3.x (3.0.0 through 3.2.0). Use New() with the desired OAS version and the corresponding Build method:
- New(parser.OASVersion20) + BuildOAS2() → *parser.OAS2Document with schemas in "definitions"
- New(parser.OASVersion3xx) + BuildOAS3() → *parser.OAS3Document with schemas in "components/schemas"
The $ref paths are automatically adjusted based on the OAS version:
- OAS 2.0: "#/definitions/", "#/parameters/", "#/responses/"
- OAS 3.x: "#/components/schemas/", "#/components/parameters/", "#/components/responses/"
Validation ¶
The builder does not perform OAS specification validation. Use the validator package to validate built documents:
result, _ := spec.BuildResult() valResult, _ := validator.ValidateWithOptions(validator.WithParsed(*result))
Quick Start ¶
Build an OAS 3.x API specification:
spec := builder.New(parser.OASVersion320).
SetTitle("My API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodGet, "/users",
builder.WithOperationID("listUsers"),
builder.WithResponse(http.StatusOK, []User{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
// doc is *parser.OAS3Document - no type assertion needed
Build an OAS 2.0 (Swagger) API specification:
spec := builder.New(parser.OASVersion20).
SetTitle("My API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodGet, "/users",
builder.WithOperationID("listUsers"),
builder.WithResponse(http.StatusOK, []User{}),
)
doc, err := spec.BuildOAS2()
if err != nil {
log.Fatal(err)
}
// doc is *parser.OAS2Document - no type assertion needed
Modifying Existing Documents ¶
Use FromDocument or FromOAS2Document to create a builder from an existing document:
// For OAS 3.x documents b := builder.FromDocument(existingOAS3Doc) b.AddOperation(http.MethodPost, "/users", ...) newDoc, _ := b.BuildOAS3() // For OAS 2.0 documents b := builder.FromOAS2Document(existingSwaggerDoc) b.AddOperation(http.MethodPost, "/users", ...) newDoc, _ := b.BuildOAS2()
Webhooks (OAS 3.1+) ¶
For OAS 3.1+ specifications, webhooks can be added using AddWebhook:
spec := builder.New(parser.OASVersion310).
SetTitle("Webhook API").
SetVersion("1.0.0").
AddWebhook("userCreated", http.MethodPost,
builder.WithRequestBody("application/json", UserEvent{}),
builder.WithResponse(http.StatusOK, struct{}{}),
)
External Documentation ¶
Add document-level external documentation using SetExternalDocs:
spec := builder.New(parser.OASVersion320).
SetTitle("My API").
SetVersion("1.0.0").
SetExternalDocs(&parser.ExternalDocs{
URL: "https://docs.example.com",
Description: "API documentation",
})
Reflection-Based Schema Generation ¶
The core feature is automatic schema generation from Go types via reflection. When you pass a Go type to WithResponse, WithRequestBody, or parameter options, the builder inspects the type structure and generates an OpenAPI-compatible schema.
Type mappings:
- string → string
- int, int32 → integer (format: int32)
- int64 → integer (format: int64)
- float32 → number (format: float)
- float64 → number (format: double)
- bool → boolean
- []T → array (items from T)
- map[string]T → object (additionalProperties from T)
- struct → object (properties from fields)
- *T → schema of T (nullable)
- time.Time → string (format: date-time)
Schema Naming ¶
Schemas are named using the Go convention of "package.TypeName" (e.g., "models.User"). This ensures uniqueness and matches Go developers' expectations for type identification. If multiple packages have the same base name (e.g., github.com/foo/models and github.com/bar/models), the full package path is used to disambiguate (e.g., "github.com_foo_models.User"). Anonymous types are named "AnonymousType".
Extensible Schema Naming ¶
The default schema naming uses "package.TypeName" format. For custom naming, use options when creating a Builder:
Built-in strategies:
// PascalCase: ModelsUser
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNaming(builder.SchemaNamingPascalCase),
)
// Type only (no package prefix): User
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNaming(builder.SchemaNamingTypeOnly),
)
Available strategies:
- SchemaNamingDefault: "package.TypeName" (e.g., models.User)
- SchemaNamingPascalCase: "PackageTypeName" (e.g., ModelsUser)
- SchemaNamingCamelCase: "packageTypeName" (e.g., modelsUser)
- SchemaNamingSnakeCase: "package_type_name" (e.g., models_user)
- SchemaNamingKebabCase: "package-type-name" (e.g., models-user)
- SchemaNamingTypeOnly: "TypeName" (e.g., User) - may cause conflicts
- SchemaNamingFullPath: "full_path_TypeName" (e.g., github.com_org_models_User)
Custom templates using Go text/template:
// Custom format: models+User
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNameTemplate(`{{.Package}}+{{.Type}}`),
)
Available template functions: pascal, camel, snake, kebab, upper, lower, title, sanitize, trimPrefix, trimSuffix, replace, join.
Custom naming function for maximum flexibility:
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNameFunc(func(ctx builder.SchemaNameContext) string {
return strings.ToUpper(ctx.Type)
}),
)
Note: RegisterTypeAs always takes precedence over any naming strategy.
Generic Types ¶
Go 1.18+ generic types are fully supported. The type parameters are included in the schema name but sanitized for URI safety by replacing brackets with underscores:
Response[User] → "builder.Response_User" Map[string,int] → "builder.Map_string_int" Response[List[User]] → "builder.Response_List_User"
This ensures $ref URIs are valid and compatible with all OpenAPI tools, which may not handle square brackets properly in schema references.
Generic type naming strategies control how generic types are formatted:
// "Of" separator: Response[User] → ResponseOfUser
spec := builder.New(parser.OASVersion320,
builder.WithGenericNaming(builder.GenericNamingOf),
)
Available generic strategies:
- GenericNamingUnderscore: "Response_User_" (default)
- GenericNamingOf: "ResponseOfUser"
- GenericNamingFor: "ResponseForUser"
- GenericNamingAngleBrackets: "Response<User>" (URI-encoded in $ref)
- GenericNamingFlattened: "ResponseUser"
For fine-grained control over generic naming:
spec := builder.New(parser.OASVersion320,
builder.WithGenericNamingConfig(builder.GenericNamingConfig{
Strategy: builder.GenericNamingOf,
ParamSeparator: "And",
ApplyBaseCasing: true,
}),
)
Struct Tags ¶
Customize schema generation with struct tags:
type User struct {
ID int64 `json:"id" oas:"description=Unique identifier"`
Name string `json:"name" oas:"minLength=1,maxLength=100"`
Email string `json:"email" oas:"format=email"`
Role string `json:"role" oas:"enum=admin|user|guest"`
}
Supported oas tag options:
- description=<text> - Field description
- format=<format> - Override format (email, uri, uuid, date, date-time, etc.)
- enum=<val1>|<val2>|... - Enumeration values
- minimum=<n>, maximum=<n> - Numeric constraints
- minLength=<n>, maxLength=<n> - String length constraints
- pattern=<regex> - String pattern
- minItems=<n>, maxItems=<n> - Array constraints
- readOnly=true, writeOnly=true - Access modifiers
- nullable=true - Explicitly nullable
- deprecated=true - Mark as deprecated
Custom Field Processors ¶
For libraries that need to support custom struct tag conventions alongside the standard oas:"..." tags, use WithSchemaFieldProcessor:
spec := builder.New(parser.OASVersion320,
builder.WithSchemaFieldProcessor(func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
return schema
}),
)
The processor is called for each struct field after the base schema is generated and after any oas:"..." tags are applied. This enables:
- Migration support from other OpenAPI libraries with different tag formats
- Custom validation tag integration (e.g., reading from validator tags)
- Documentation generators pulling from godoc-style comments
- Framework integration with existing struct tag conventions
Multiple processors can be composed using ComposeSchemaFieldProcessors:
composed := builder.ComposeSchemaFieldProcessors(descProcessor, enumProcessor) spec := builder.New(parser.OASVersion320, builder.WithSchemaFieldProcessor(composed))
Required Fields ¶
Required fields are determined by:
- Non-pointer fields without omitempty are required
- Fields with oas:"required=true" are explicitly required
- Fields with oas:"required=false" are explicitly optional
Operation Responses ¶
Note: OpenAPI requires at least one response per operation. If no responses are defined, the resulting spec will fail OAS validation. Always use WithResponse() or WithDefaultResponse() to add responses to operations.
Parameter Constraints ¶
Add validation constraints to parameters using WithParam* options:
spec.AddOperation(http.MethodGet, "/pets",
builder.WithQueryParam("limit", int32(0),
builder.WithParamDescription("Maximum number of pets to return"),
builder.WithParamMinimum(1),
builder.WithParamMaximum(100),
builder.WithParamDefault(20),
),
builder.WithQueryParam("status", string(""),
builder.WithParamEnum("available", "pending", "sold"),
),
builder.WithQueryParam("name", string(""),
builder.WithParamMinLength(1),
builder.WithParamMaxLength(50),
builder.WithParamPattern("^[a-zA-Z]+$"),
),
)
Supported parameter constraint options:
- WithParamMinimum(min float64) - Minimum value for numeric parameters
- WithParamMaximum(max float64) - Maximum value for numeric parameters
- WithParamExclusiveMinimum(exclusive bool) - Whether minimum is exclusive
- WithParamExclusiveMaximum(exclusive bool) - Whether maximum is exclusive
- WithParamMultipleOf(value float64) - Value must be a multiple of this (must be > 0)
- WithParamMinLength(min int) - Minimum length for string parameters (must be >= 0)
- WithParamMaxLength(max int) - Maximum length for string parameters (must be >= 0)
- WithParamPattern(pattern string) - Regex pattern for string parameters (validated at build time)
- WithParamMinItems(min int) - Minimum items for array parameters (must be >= 0)
- WithParamMaxItems(max int) - Maximum items for array parameters (must be >= 0)
- WithParamUniqueItems(unique bool) - Whether array items must be unique
- WithParamEnum(values ...any) - Allowed enumeration values
- WithParamDefault(value any) - Default value for the parameter
Explicit Type and Format Overrides ¶
Override the inferred OpenAPI type or format when the Go type doesn't map directly to your desired schema:
spec.AddOperation(http.MethodGet, "/users/{user_id}",
builder.WithPathParam("user_id", "",
builder.WithParamFormat("uuid"),
),
builder.WithQueryParam("version", 0,
builder.WithParamType("integer"),
builder.WithParamFormat("int64"),
),
)
Available type/format override options:
- WithParamType(typeName string) - Override inferred type (string, integer, number, boolean, array, object)
- WithParamFormat(format string) - Override inferred format (uuid, email, date-time, byte, binary, etc.)
- WithParamSchema(schema *parser.Schema) - Full schema override (highest precedence)
Precedence rules:
- WithParamSchema takes highest precedence (complete replacement)
- WithParamType replaces the inferred type
- WithParamFormat replaces the inferred format
Constraint validation is performed when building the document. The following rules are enforced:
- minimum must be <= maximum (if both are set)
- minLength must be <= maxLength (if both are set)
- minItems must be <= maxItems (if both are set)
- minLength, maxLength, minItems, maxItems must be non-negative
- multipleOf must be greater than 0
- pattern must be a valid regex
Form Parameters ¶
Form parameters are handled differently across OAS versions. The builder provides a unified WithFormParam method that automatically adapts to the target OAS version:
spec.AddOperation(http.MethodPost, "/login",
builder.WithFormParam("username", string(""),
builder.WithParamRequired(true),
builder.WithParamMinLength(3),
),
builder.WithFormParam("password", string(""),
builder.WithParamRequired(true),
builder.WithParamMinLength(8),
),
builder.WithResponse(http.StatusOK, LoginResponse{}),
)
OAS 2.0: Form parameters are created as parameters with in="formData":
parameters:
- name: username
in: formData
type: string
required: true
minLength: 3
OAS 3.x: Form parameters are added to the request body with application/x-www-form-urlencoded:
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
username:
type: string
minLength: 3
required:
- username
All parameter constraints and options work with form parameters. If a request body already exists (e.g., for multipart/form-data), form parameters are merged into it with the application/x-www-form-urlencoded content type.
OAS Version Differences for Constraints ¶
The builder handles constraint placement automatically based on the OAS version:
OAS 3.x (3.0.0+): Constraints are applied to the parameter's Schema field. The OAS 3.x specification separates the parameter metadata (name, location, required) from the value schema (type, format, constraints). This is the modern approach:
parameters:
- name: limit
in: query
schema:
type: integer
minimum: 1 # Constraint on schema
maximum: 100 # Constraint on schema
OAS 2.0 (Swagger): Constraints are applied directly to the Parameter object. In OAS 2.0, non-body parameters have type and constraints as top-level fields:
parameters:
- name: limit
in: query
type: integer
minimum: 1 # Constraint on parameter
maximum: 100 # Constraint on parameter
The builder abstracts this difference, allowing you to use the same WithParam* options regardless of target OAS version.
Custom Content Types ¶
Use WithResponseContentType to specify content types other than the default "application/json":
spec.AddOperation(http.MethodGet, "/users",
builder.WithResponse(http.StatusOK, []User{},
builder.WithResponseContentType("application/xml"),
),
)
For multiple content types, use WithRequestBodyContentTypes or WithResponseContentTypes:
spec.AddOperation(http.MethodPost, "/users",
builder.WithRequestBodyContentTypes(
[]string{"application/json", "application/xml"},
User{},
),
builder.WithResponseContentTypes(http.StatusOK,
[]string{"application/json", "application/xml"},
User{},
),
)
Vendor Extensions ¶
Add vendor extensions (x-* fields) to operations, parameters, responses, and request bodies:
spec.AddOperation(http.MethodGet, "/users",
builder.WithOperationExtension("x-rate-limit", 100),
builder.WithQueryParam("limit", int32(0),
builder.WithParamExtension("x-ui-widget", "slider"),
),
builder.WithResponse(http.StatusOK, []User{},
builder.WithResponseExtension("x-cache-ttl", 3600),
),
)
spec.AddOperation(http.MethodPost, "/users",
builder.WithRequestBody("application/json", User{},
builder.WithRequestBodyExtension("x-codegen-request-body-name", "user"),
),
)
OAS 2.0 Specific Options ¶
For OAS 2.0 specifications, additional options are available:
spec.AddOperation(http.MethodPost, "/users",
builder.WithConsumes("application/json", "application/xml"),
builder.WithProduces("application/json"),
builder.WithQueryParam("tags", []string{},
builder.WithParamCollectionFormat("csv"), // csv, ssv, tsv, pipes, multi
builder.WithParamAllowEmptyValue(true),
),
)
See the examples in example_test.go for more patterns.
Semantic Schema Deduplication ¶
The builder can automatically identify and consolidate structurally identical schemas, reducing document size when multiple types converge to the same structure.
Enable via option:
spec := builder.New(parser.OASVersion320,
builder.WithSemanticDeduplication(true),
)
// Add schemas that happen to be structurally identical
spec.AddOperation(http.MethodGet, "/addresses",
builder.WithResponse(http.StatusOK, []Address{}),
)
spec.AddOperation(http.MethodGet, "/locations",
builder.WithResponse(http.StatusOK, []Location{}), // Same structure as Address
)
doc, _ := spec.BuildOAS3()
// Only one schema exists; all $refs point to the canonical (alphabetically first) name
Or call manually before building:
spec.DeduplicateSchemas() doc, _ := spec.BuildOAS3()
Deduplication compares schemas structurally, ignoring metadata fields (title, description, example, deprecated). When duplicates are found, the alphabetically first name becomes canonical, and all references are automatically rewritten.
Server Builder ¶
The ServerBuilder extends Builder to produce runnable HTTP servers directly from the fluent API. This enables a "code-first" development workflow where developers define API operations and their implementations in a single fluent API.
Create a server builder:
srv := builder.NewServerBuilder(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(listPetsHandler), // Inline handler registration
builder.WithResponse(http.StatusOK, []Pet{}),
)
result, err := srv.BuildServer()
if err != nil {
log.Fatal(err)
}
http.ListenAndServe(":8080", result.Handler)
The ServerBuilder provides:
- Automatic request validation using the httpvalidator package
- Type-safe response construction with response helpers (JSON, NoContent, Error, Redirect, Stream)
- Middleware support via the Use method
- Flexible routing using the stdlib net/http router
- Recovery middleware for panic handling
- Request logging middleware
Handler Registration ¶
Register handlers inline using WithHandler in AddOperation:
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(func(ctx context.Context, req *builder.Request) builder.Response {
// req.PathParams, req.QueryParams contain validated parameters
// req.Body contains the unmarshaled request body
return builder.JSON(http.StatusOK, pets)
}),
builder.WithResponse(http.StatusOK, []Pet{}),
)
Or register handlers dynamically using Handle or HandleFunc:
// Using the typed handler signature with method and path
srv.Handle(http.MethodGet, "/pets", listPetsHandler)
// Using standard http.HandlerFunc for simpler operations
srv.HandleFunc(http.MethodGet, "/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
Operations without registered handlers return 501 Not Implemented at runtime.
Response Helpers ¶
The builder provides convenient response constructors:
// JSON response
return builder.JSON(http.StatusOK, data)
// No content response
return builder.NoContent()
// Error response
return builder.Error(http.StatusNotFound, "not found")
// Redirect response
return builder.Redirect(http.StatusMovedPermanently, "/new-location")
// Streaming response
return builder.Stream(http.StatusOK, "application/octet-stream", reader)
// Fluent response builder
return builder.NewResponse(http.StatusOK).
Header("X-Custom", "value").
JSON(data)
Server Configuration ¶
Configure the server builder with options:
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation(), // Disable request validation builder.WithRecovery(), // Enable panic recovery builder.WithRequestLogging(loggingFunc), // Enable request logging builder.WithErrorHandler(customErrorHandler), // Custom error handler builder.WithNotFoundHandler(custom404Handler), // Custom 404 handler )
Middleware ¶
Add middleware to the server. Middleware is applied in order: first added = outermost.
srv.Use(corsMiddleware, authMiddleware, loggingMiddleware)
Testing ¶
The package provides testing utilities:
result := srv.MustBuildServer()
test := builder.NewServerTest(result)
// Execute requests
rec := test.Execute(builder.NewTestRequest(http.MethodGet, "/pets"))
// JSON helpers
var pets []Pet
rec, err := test.GetJSON("/pets", &pets)
rec, err := test.PostJSON("/pets", newPet, &created)
// Stub handlers for testing
srv.Handle(http.MethodGet, "/pets", builder.StubHandler(builder.JSON(http.StatusOK, mockPets)))
Related Packages ¶
The builder integrates with other oastools packages:
- github.com/erraggy/oastools/parser - Builder generates parser-compatible documents
- github.com/erraggy/oastools/validator - Validate built specifications
- github.com/erraggy/oastools/fixer - Fix common validation errors in built specifications
- github.com/erraggy/oastools/converter - Convert built specs between OAS versions
- github.com/erraggy/oastools/joiner - Join built specs with existing documents
- github.com/erraggy/oastools/differ - Compare built specs with other specifications
- github.com/erraggy/oastools/generator - Generate code from built specifications
- github.com/erraggy/oastools/httpvalidator - Runtime request/response validation
Example ¶
Example demonstrates basic builder usage.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodGet, "/pets",
builder.WithOperationID("listPets"),
builder.WithResponse(http.StatusOK, []Pet{}),
)
// Use BuildOAS3() for type-safe access - no type assertion needed
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
fmt.Printf("OpenAPI: %s\n", doc.OpenAPI)
fmt.Printf("Title: %s\n", doc.Info.Title)
fmt.Printf("Paths: %d\n", len(doc.Paths))
}
Output: OpenAPI: 3.2.0 Title: Pet Store API Paths: 1
Example (CompleteAPI) ¶
Example_completeAPI demonstrates a complete API specification.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
// Error represents an API error.
type Error struct {
Code int32 `json:"code" oas:"description=Error code"`
Message string `json:"message" oas:"description=Error message"`
}
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0").
SetDescription("A sample Pet Store API demonstrating the builder package").
AddServer("https://api.petstore.example.com/v1",
builder.WithServerDescription("Production server"),
).
AddTag("pets", builder.WithTagDescription("Operations about pets")).
AddAPIKeySecurityScheme("api_key", "header", "X-API-Key", "API key").
SetSecurity(builder.SecurityRequirement("api_key"))
// List pets
spec.AddOperation(http.MethodGet, "/pets",
builder.WithOperationID("listPets"),
builder.WithSummary("List all pets"),
builder.WithTags("pets"),
builder.WithQueryParam("limit", int32(0),
builder.WithParamDescription("Maximum number of pets to return"),
),
builder.WithResponse(http.StatusOK, []Pet{},
builder.WithResponseDescription("A list of pets"),
),
builder.WithResponse(http.StatusInternalServerError, Error{},
builder.WithResponseDescription("Unexpected error"),
),
)
// Get pet by ID
spec.AddOperation(http.MethodGet, "/pets/{petId}",
builder.WithOperationID("getPet"),
builder.WithSummary("Get a pet by ID"),
builder.WithTags("pets"),
builder.WithPathParam("petId", int64(0),
builder.WithParamDescription("The ID of the pet to retrieve"),
),
builder.WithResponse(http.StatusOK, Pet{},
builder.WithResponseDescription("The requested pet"),
),
builder.WithResponse(http.StatusNotFound, Error{},
builder.WithResponseDescription("Pet not found"),
),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Title: %s\n", doc.Info.Title)
fmt.Printf("Paths: %d\n", len(doc.Paths))
fmt.Printf("Tags: %d\n", len(doc.Tags))
fmt.Printf("Schemas: %d\n", len(doc.Components.Schemas))
}
Output: Title: Pet Store API Paths: 2 Tags: 1 Schemas: 2
Example (ComposeSchemaFieldProcessors) ¶
Example_composeSchemaFieldProcessors demonstrates composing multiple field processors. This is useful when you have separate concerns that each need to process struct tags, such as description handling, enum parsing, and numeric constraint validation. Processors execute in order, with each receiving the schema from the previous processor.
package main
import (
"fmt"
"log"
"net/http"
"reflect"
"strconv"
"strings"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// Define a struct with various legacy tags
type ServerConfig struct {
Host string `json:"host" description:"Server hostname"`
Port int `json:"port" description:"Server port" minimum:"1" maximum:"65535"`
Timeout int `json:"timeout" description:"Request timeout in seconds" minimum:"1"`
Mode string `json:"mode" description:"Operating mode" enum:"development|staging|production"`
}
// Processor for description tags
descriptionProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
return schema
}
// Processor for enum tags (pipe-separated)
enumProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if enumStr := field.Tag.Get("enum"); enumStr != "" {
values := strings.Split(enumStr, "|")
schema.Enum = make([]any, len(values))
for i, v := range values {
schema.Enum[i] = strings.TrimSpace(v)
}
}
return schema
}
// Processor for numeric constraint tags
numericProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if minStr := field.Tag.Get("minimum"); minStr != "" {
if min, err := strconv.ParseFloat(minStr, 64); err == nil {
schema.Minimum = &min
}
}
if maxStr := field.Tag.Get("maximum"); maxStr != "" {
if max, err := strconv.ParseFloat(maxStr, 64); err == nil {
schema.Maximum = &max
}
}
return schema
}
// Compose all processors into a single processor
composedProcessor := builder.ComposeSchemaFieldProcessors(
descriptionProcessor,
enumProcessor,
numericProcessor,
)
// Build specification with the composed processor
spec := builder.New(parser.OASVersion320,
builder.WithSchemaFieldProcessor(composedProcessor),
).
SetTitle("Server Config API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/config",
builder.WithResponse(http.StatusOK, ServerConfig{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
// Access the generated schema
configSchema := doc.Components.Schemas["builder_test.ServerConfig"]
hostSchema := configSchema.Properties["host"]
portSchema := configSchema.Properties["port"]
modeSchema := configSchema.Properties["mode"]
fmt.Printf("Host description: %s\n", hostSchema.Description)
fmt.Printf("Port description: %s\n", portSchema.Description)
fmt.Printf("Port minimum: %.0f\n", *portSchema.Minimum)
fmt.Printf("Port maximum: %.0f\n", *portSchema.Maximum)
fmt.Printf("Mode description: %s\n", modeSchema.Description)
fmt.Printf("Mode enum: %v\n", modeSchema.Enum)
}
Output: Host description: Server hostname Port description: Server port Port minimum: 1 Port maximum: 65535 Mode description: Operating mode Mode enum: [development staging production]
Example (FromDocument) ¶
Example_fromDocument demonstrates modifying an existing document.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// Create an existing document (in real code, this would be parsed from a file)
existingDoc := &parser.OAS3Document{
OpenAPI: "3.0.3",
Info: &parser.Info{
Title: "Existing API",
Version: "1.0.0",
},
Paths: parser.Paths{
"/existing": &parser.PathItem{
Get: &parser.Operation{
OperationID: "existingOperation",
Responses: &parser.Responses{
Codes: map[string]*parser.Response{
"200": {
Description: "Existing response",
},
},
},
},
},
},
}
// Create builder from existing document and add new operations
spec := builder.FromDocument(existingDoc)
type HealthResponse struct {
Status string `json:"status"`
}
spec.AddOperation(http.MethodGet, "/health",
builder.WithOperationID("healthCheck"),
builder.WithResponse(http.StatusOK, HealthResponse{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Paths: %d\n", len(doc.Paths))
fmt.Printf("Has /existing: %v\n", doc.Paths["/existing"] != nil)
fmt.Printf("Has /health: %v\n", doc.Paths["/health"] != nil)
}
Output: Paths: 2 Has /existing: true Has /health: true
Example (GenericNamingConfig) ¶
Example_genericNamingConfig demonstrates fine-grained generic type naming configuration. Use WithGenericNamingConfig for full control over how generic type parameters are formatted.
package main
import (
"fmt"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
// Configure generic naming with custom settings.
// This example uses GenericNamingOf strategy with "And" as the separator
// between multiple type parameters.
//
// For generic types like Response[User], this would produce "ResponseOfUser".
// For types like Map[string,int], this would produce "MapOfStringAndOfInt".
spec := builder.New(parser.OASVersion320,
builder.WithGenericNamingConfig(builder.GenericNamingConfig{
Strategy: builder.GenericNamingOf,
ParamSeparator: "And",
ApplyBaseCasing: true,
}),
).
SetTitle("Example API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/pets",
builder.WithResponse(http.StatusOK, []Pet{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Title: %s\n", doc.Info.Title)
fmt.Printf("Schemas: %d\n", len(doc.Components.Schemas))
}
Output: Title: Example API Schemas: 1
Example (SchemaGeneration) ¶
Example_schemaGeneration demonstrates automatic schema generation.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
type Address struct {
Street string `json:"street"`
City string `json:"city"`
Country string `json:"country"`
}
type Customer struct {
ID int64 `json:"id"`
Name string `json:"name"`
Email string `json:"email" oas:"format=email"`
Address Address `json:"address"`
}
spec := builder.New(parser.OASVersion320).
SetTitle("Customer API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/customers/{id}",
builder.WithOperationID("getCustomer"),
builder.WithPathParam("id", int64(0)),
builder.WithResponse(http.StatusOK, Customer{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
// Both Customer and Address schemas are auto-generated with package-qualified names
_, hasCustomer := doc.Components.Schemas["builder_test.Customer"]
_, hasAddress := doc.Components.Schemas["builder_test.Address"]
fmt.Printf("Has Customer schema: %v\n", hasCustomer)
fmt.Printf("Has Address schema: %v\n", hasAddress)
}
Output: Has Customer schema: true Has Address schema: true
Example (SchemaNamingCustomFunc) ¶
Example_schemaNamingCustomFunc demonstrates custom function-based schema naming. Use WithSchemaNameFunc for maximum flexibility when you need programmatic control over schema names based on type metadata.
package main
import (
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
type Order struct {
ID int64 `json:"id"`
Total float64 `json:"total"`
Status string `json:"status"`
}
// Custom naming function that prefixes schemas with API version
// and converts the type name to uppercase
apiVersion := "V2"
customNamer := func(ctx builder.SchemaNameContext) string {
// Use the type name, converting to uppercase for emphasis
return apiVersion + "_" + ctx.Type
}
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNameFunc(customNamer),
).
SetTitle("Order API").
SetVersion("2.0.0").
AddOperation(http.MethodGet, "/orders",
builder.WithResponse(http.StatusOK, Order{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
fmt.Println("Error:", err)
return
}
// Print schema names
for name := range doc.Components.Schemas {
fmt.Println("Schema:", name)
}
}
Output: Schema: V2_Order
Example (SchemaNamingPascalCase) ¶
Example_schemaNamingPascalCase demonstrates PascalCase schema naming strategy. With SchemaNamingPascalCase, "package.TypeName" becomes "PackageTypeName".
package main
import (
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNaming(builder.SchemaNamingPascalCase),
).
SetTitle("Example API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/users",
builder.WithResponse(http.StatusOK, User{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
fmt.Println("Error:", err)
return
}
// Print schema names
for name := range doc.Components.Schemas {
fmt.Println("Schema:", name)
}
}
Output: Schema: BuilderTestUser
Example (SchemaNamingTemplate) ¶
Example_schemaNamingTemplate demonstrates custom template-based schema naming. Templates use Go text/template syntax with helper functions like pascal, camel, etc.
package main
import (
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
type Product struct {
ID int `json:"id"`
Price float64 `json:"price"`
}
// Custom template: prefix with "API" and use pascal case
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNameTemplate(`API{{pascal .Type}}`),
).
SetTitle("Example API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/products",
builder.WithResponse(http.StatusOK, Product{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
fmt.Println("Error:", err)
return
}
// Print schema names
for name := range doc.Components.Schemas {
fmt.Println("Schema:", name)
}
}
Output: Schema: APIProduct
Example (SemanticDeduplication) ¶
Example_semanticDeduplication demonstrates automatic consolidation of identical schemas. When multiple Go types generate structurally identical schemas, enabling semantic deduplication identifies these duplicates and consolidates them to a single canonical schema.
package main
import (
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// Define types that are structurally identical but have different names
type UserID struct {
Value int64 `json:"value"`
}
type CustomerID struct {
Value int64 `json:"value"`
}
type OrderID struct {
Value int64 `json:"value"`
}
// Build specification with semantic deduplication enabled
spec := builder.New(parser.OASVersion320,
builder.WithSemanticDeduplication(true),
).
SetTitle("ID API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/users/{id}",
builder.WithResponse(http.StatusOK, UserID{}),
).
AddOperation(http.MethodGet, "/customers/{id}",
builder.WithResponse(http.StatusOK, CustomerID{}),
).
AddOperation(http.MethodGet, "/orders/{id}",
builder.WithResponse(http.StatusOK, OrderID{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
fmt.Println("Error:", err)
return
}
// Without deduplication: 3 schemas (UserID, CustomerID, OrderID)
// With deduplication: 1 schema (the alphabetically first canonical name)
fmt.Printf("Title: %s\n", doc.Info.Title)
fmt.Printf("Schemas: %d\n", len(doc.Components.Schemas))
fmt.Printf("Operations: %d\n", len(doc.Paths))
}
Output: Title: ID API Schemas: 1 Operations: 3
Example (ServerBuilder) ¶
Example_serverBuilder demonstrates building a runnable HTTP server from an OpenAPI spec. ServerBuilder extends Builder to create an http.Handler with automatic routing, request validation, and typed request/response handling.
package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
type Message struct {
Text string `json:"text"`
}
// Create a server builder (extends Builder with server capabilities)
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Message API").
SetVersion("1.0.0")
// Add operation and register handler
srv.AddOperation(http.MethodGet, "/message",
builder.WithOperationID("getMessage"),
builder.WithResponse(http.StatusOK, Message{}),
)
srv.Handle(http.MethodGet, "/message", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, Message{Text: "Hello, World!"})
})
// Build the server
result, err := srv.BuildServer()
if err != nil {
log.Fatal(err)
}
// result.Handler is a standard http.Handler ready to serve
// result.Spec contains the generated OpenAPI document
fmt.Printf("Handler type: %T\n", result.Handler)
fmt.Printf("Has spec: %v\n", result.Spec != nil)
}
Output: Handler type: http.HandlerFunc Has spec: true
Example (ServerBuilderCRUD) ¶
Example_serverBuilderCRUD demonstrates a complete CRUD API with ServerBuilder. This shows the typical pattern of defining operations, registering handlers, and building a production-ready HTTP server.
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
// Create server with validation disabled for this example
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Pet Store API").
SetVersion("1.0.0")
// Define CRUD operations
srv.AddOperation(http.MethodGet, "/pets",
builder.WithOperationID("listPets"),
builder.WithResponse(http.StatusOK, []Pet{}),
)
srv.AddOperation(http.MethodPost, "/pets",
builder.WithOperationID("createPet"),
builder.WithRequestBody("application/json", Pet{}),
builder.WithResponse(http.StatusCreated, Pet{}),
)
srv.AddOperation(http.MethodGet, "/pets/{petId}",
builder.WithOperationID("getPet"),
builder.WithPathParam("petId", int64(0)),
builder.WithResponse(http.StatusOK, Pet{}),
)
srv.AddOperation(http.MethodDelete, "/pets/{petId}",
builder.WithOperationID("deletePet"),
builder.WithPathParam("petId", int64(0)),
builder.WithResponse(http.StatusNoContent, nil),
)
// Register handlers for each operation
srv.Handle(http.MethodGet, "/pets", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, []Pet{{ID: 1, Name: "Fluffy"}})
})
srv.Handle(http.MethodPost, "/pets", func(_ context.Context, req *builder.Request) builder.Response {
// req.Body contains the parsed request body
return builder.JSON(http.StatusCreated, req.Body)
})
srv.Handle(http.MethodGet, "/pets/{petId}", func(_ context.Context, req *builder.Request) builder.Response {
// req.PathParams contains typed path parameters
_ = req.PathParams["petId"]
return builder.JSON(http.StatusOK, Pet{ID: 1, Name: "Fluffy"})
})
srv.Handle(http.MethodDelete, "/pets/{petId}", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.NoContent()
})
result := srv.MustBuildServer()
// Verify the spec was generated correctly
doc := result.Spec.(*parser.OAS3Document)
fmt.Printf("Paths: %d\n", len(doc.Paths))
fmt.Printf("Operations: listPets=%v, createPet=%v, getPet=%v, deletePet=%v\n",
doc.Paths["/pets"].Get != nil,
doc.Paths["/pets"].Post != nil,
doc.Paths["/pets/{petId}"].Get != nil,
doc.Paths["/pets/{petId}"].Delete != nil,
)
}
Output: Paths: 2 Operations: listPets=true, createPet=true, getPet=true, deletePet=true
Example (ServerBuilderFromBuilder) ¶
Example_serverBuilderFromBuilder demonstrates creating a ServerBuilder from an existing Builder. This allows converting a specification into a runnable server.
package main
import (
"context"
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// First create a specification with Builder
spec := builder.New(parser.OASVersion320).
SetTitle("Converted API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodGet, "/status",
builder.WithOperationID("getStatus"),
builder.WithResponse(http.StatusOK, map[string]string{}),
)
// Convert to ServerBuilder to add handlers
srv := builder.FromBuilder(spec, builder.WithoutValidation())
srv.Handle(http.MethodGet, "/status", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, map[string]string{"status": "ok"})
})
result := srv.MustBuildServer()
doc := result.Spec.(*parser.OAS3Document)
fmt.Printf("Title: %s\n", doc.Info.Title)
fmt.Printf("Has handler: %v\n", result.Handler != nil)
}
Output: Title: Converted API Has handler: true
Example (ServerBuilderMiddleware) ¶
Example_serverBuilderMiddleware demonstrates adding middleware to the server. Middleware is applied in order: first added = outermost (executes first).
package main
import (
"context"
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Middleware Demo API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/hello",
builder.WithOperationID("hello"),
builder.WithResponse(http.StatusOK, map[string]string{}),
)
srv.Handle(http.MethodGet, "/hello", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, map[string]string{"message": "hello"})
})
// Add logging middleware
srv.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Log before handling (would use real logger in production)
_ = fmt.Sprintf("Request: %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
})
// Add CORS middleware
srv.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
next.ServeHTTP(w, r)
})
})
result := srv.MustBuildServer()
fmt.Printf("Server with middleware: %v\n", result.Handler != nil)
}
Output: Server with middleware: true
Example (ServerBuilderResponseBuilder) ¶
Example_serverBuilderResponseBuilder demonstrates the fluent ResponseBuilder for constructing complex responses with headers and custom content types.
package main
import (
"context"
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Custom Response API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/custom",
builder.WithOperationID("customResponse"),
builder.WithResponse(http.StatusOK, nil),
)
// Use ResponseBuilder for complex responses
srv.Handle(http.MethodGet, "/custom", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.NewResponse(http.StatusOK).
Header("X-Custom-Header", "custom-value").
Header("X-Request-ID", "12345").
JSON(map[string]string{"message": "hello"})
})
result := srv.MustBuildServer()
fmt.Printf("Server built: %v\n", result.Handler != nil)
}
Output: Server built: true
Example (ServerBuilderResponses) ¶
Example_serverBuilderResponses demonstrates the various response helpers available. ServerBuilder provides convenience functions for common HTTP response patterns.
package main
import (
"context"
"fmt"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Response Demo API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/json",
builder.WithOperationID("jsonResponse"),
builder.WithResponse(http.StatusOK, map[string]string{}),
)
srv.AddOperation(http.MethodGet, "/error",
builder.WithOperationID("errorResponse"),
builder.WithResponse(http.StatusBadRequest, map[string]string{}),
)
srv.AddOperation(http.MethodGet, "/redirect",
builder.WithOperationID("redirectResponse"),
builder.WithResponse(http.StatusFound, nil),
)
srv.AddOperation(http.MethodDelete, "/resource",
builder.WithOperationID("noContent"),
builder.WithResponse(http.StatusNoContent, nil),
)
// JSON response with status code
srv.Handle(http.MethodGet, "/json", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, map[string]string{"status": "ok"})
})
// Error response with message
srv.Handle(http.MethodGet, "/error", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.Error(http.StatusBadRequest, "invalid request")
})
// Redirect response
srv.Handle(http.MethodGet, "/redirect", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.Redirect(http.StatusFound, "/new-location")
})
// No content response (204)
srv.Handle(http.MethodDelete, "/resource", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.NoContent()
})
result := srv.MustBuildServer()
doc := result.Spec.(*parser.OAS3Document)
fmt.Printf("Operations defined: %d\n", len(doc.Paths))
}
Output: Operations defined: 4
Example (ServerBuilderTesting) ¶
Example_serverBuilderTesting demonstrates the testing utilities for ServerBuilder. These helpers simplify writing tests for API handlers without starting a real server.
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
srv := builder.NewServerBuilder(parser.OASVersion320, builder.WithoutValidation()).
SetTitle("Test API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/pets",
builder.WithOperationID("listPets"),
builder.WithResponse(http.StatusOK, []Pet{}),
)
srv.Handle(http.MethodGet, "/pets", func(_ context.Context, _ *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, []Pet{{ID: 1, Name: "Fluffy"}})
})
result := srv.MustBuildServer()
// Create a test helper
test := builder.NewServerTest(result)
// Use GetJSON for simple GET requests with JSON response
var pets []Pet
rec, err := test.GetJSON("/pets", &pets)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %d\n", rec.Code)
fmt.Printf("Pets returned: %d\n", len(pets))
fmt.Printf("First pet: %s\n", pets[0].Name)
}
Output: Status: 200 Pets returned: 1 First pet: Fluffy
Example (ServerBuilderWithValidation) ¶
Example_serverBuilderWithValidation demonstrates enabling request validation. When validation is enabled, requests are validated against the OpenAPI spec before reaching the handler.
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
srv := builder.NewServerBuilder(parser.OASVersion320,
builder.WithValidationConfig(builder.ValidationConfig{
IncludeRequestValidation: true,
StrictMode: false,
}),
).
SetTitle("Validated API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodPost, "/pets",
builder.WithOperationID("createPet"),
builder.WithRequestBody("application/json", Pet{}),
builder.WithResponse(http.StatusCreated, Pet{}),
)
srv.Handle(http.MethodPost, "/pets", func(_ context.Context, req *builder.Request) builder.Response {
// Request has already been validated at this point
return builder.JSON(http.StatusCreated, req.Body)
})
result, err := srv.BuildServer()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Validation enabled: %v\n", result.Validator != nil)
}
Output: Validation enabled: true
Example (WithComplexRawSchema) ¶
Example_withComplexRawSchema demonstrates using raw schemas for complex multipart uploads.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Complex Upload API").
SetVersion("1.0.0")
// Complex multipart schema with file and metadata
uploadSchema := &parser.Schema{
Type: "object",
Properties: map[string]*parser.Schema{
"file": {
Type: "string",
Format: "binary",
Description: "The file data",
},
"metadata": {
Type: "object",
Properties: map[string]*parser.Schema{
"filename": {
Type: "string",
Description: "Original filename",
},
"tags": {
Type: "array",
Items: &parser.Schema{Type: "string"},
Description: "File tags",
},
},
},
},
Required: []string{"file"},
}
spec.AddOperation(http.MethodPost, "/upload-with-metadata",
builder.WithOperationID("uploadWithMetadata"),
builder.WithRequestBodyRawSchema("multipart/form-data", uploadSchema,
builder.WithRequired(true),
builder.WithRequestDescription("Upload file with metadata"),
),
builder.WithResponse(http.StatusCreated, struct {
ID string `json:"id"`
}{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
rb := doc.Paths["/upload-with-metadata"].Post.RequestBody
schema := rb.Content["multipart/form-data"].Schema
fmt.Printf("Request body required: %v\n", rb.Required)
fmt.Printf("Has file property: %v\n", schema.Properties["file"] != nil)
fmt.Printf("Has metadata property: %v\n", schema.Properties["metadata"] != nil)
fmt.Printf("File format: %s\n", schema.Properties["file"].Format)
fmt.Printf("Required fields: %v\n", schema.Required)
}
Output: Request body required: true Has file property: true Has metadata property: true File format: binary Required fields: [file]
Example (WithFileUpload) ¶
Example_withFileUpload demonstrates file upload support using WithFileParam.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// OAS 3.x file upload with multipart/form-data
spec := builder.New(parser.OASVersion320).
SetTitle("File Upload API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodPost, "/upload",
builder.WithOperationID("uploadFile"),
builder.WithFileParam("file",
builder.WithParamRequired(true),
builder.WithParamDescription("File to upload"),
),
builder.WithFormParam("description", "",
builder.WithParamDescription("File description"),
),
builder.WithResponse(http.StatusOK, struct {
Success bool `json:"success"`
FileID string `json:"file_id"`
}{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
rb := doc.Paths["/upload"].Post.RequestBody
schema := rb.Content["multipart/form-data"].Schema
fmt.Printf("Has file property: %v\n", schema.Properties["file"] != nil)
fmt.Printf("File type: %s\n", schema.Properties["file"].Type)
fmt.Printf("File format: %s\n", schema.Properties["file"].Format)
fmt.Printf("Has description: %v\n", schema.Properties["description"] != nil)
fmt.Printf("Required: %v\n", schema.Required)
}
Output: Has file property: true File type: string File format: binary Has description: true Required: [file]
Example (WithFormParameters) ¶
Example_withFormParameters demonstrates using form parameters. Form parameters work differently in OAS 2.0 vs 3.x:
- OAS 2.0: parameters with in="formData"
- OAS 3.x: request body with application/x-www-form-urlencoded
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Error represents an API error.
type Error struct {
Code int32 `json:"code" oas:"description=Error code"`
Message string `json:"message" oas:"description=Error message"`
}
func main() {
// OAS 3.x example - form parameters become request body
spec := builder.New(parser.OASVersion320).
SetTitle("Login API").
SetVersion("1.0.0")
type LoginResponse struct {
Token string `json:"token"`
ExpiresIn int32 `json:"expires_in"`
}
spec.AddOperation(http.MethodPost, "/login",
builder.WithOperationID("login"),
builder.WithSummary("User login"),
// Form parameters are automatically converted to request body schema
builder.WithFormParam("username", "",
builder.WithParamDescription("User's username"),
builder.WithParamRequired(true),
builder.WithParamMinLength(3),
builder.WithParamMaxLength(20),
),
builder.WithFormParam("password", "",
builder.WithParamDescription("User's password"),
builder.WithParamRequired(true),
builder.WithParamMinLength(8),
),
builder.WithFormParam("remember_me", false,
builder.WithParamDescription("Remember login session"),
builder.WithParamDefault(false),
),
builder.WithResponse(http.StatusOK, LoginResponse{},
builder.WithResponseDescription("Successful login"),
),
builder.WithResponse(http.StatusUnauthorized, Error{},
builder.WithResponseDescription("Invalid credentials"),
),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
// Form parameters are in the request body
rb := doc.Paths["/login"].Post.RequestBody
mediaType := rb.Content["application/x-www-form-urlencoded"]
fmt.Printf("Request body content type: application/x-www-form-urlencoded\n")
fmt.Printf("Form fields: %d\n", len(mediaType.Schema.Properties))
fmt.Printf("Required fields: %d\n", len(mediaType.Schema.Required))
fmt.Printf("Has username: %v\n", mediaType.Schema.Properties["username"] != nil)
fmt.Printf("Has password: %v\n", mediaType.Schema.Properties["password"] != nil)
fmt.Printf("Has remember_me: %v\n", mediaType.Schema.Properties["remember_me"] != nil)
}
Output: Request body content type: application/x-www-form-urlencoded Form fields: 3 Required fields: 2 Has username: true Has password: true Has remember_me: true
Example (WithParamTypeFormatOverride) ¶
Example_withParamTypeFormatOverride demonstrates explicit type and format overrides. Use WithParamType and WithParamFormat when the Go type doesn't map directly to the desired OpenAPI type/format, such as using a string for UUID identifiers or representing binary data as base64.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("ID API").
SetVersion("1.0.0")
spec.AddOperation(http.MethodGet, "/users/{user_id}",
builder.WithOperationID("getUser"),
// String with UUID format (inferred type is string, explicit format)
builder.WithPathParam("user_id", "",
builder.WithParamFormat("uuid"),
builder.WithParamDescription("User UUID identifier"),
),
// Override type to integer with int64 format
builder.WithQueryParam("version", 0,
builder.WithParamType("integer"),
builder.WithParamFormat("int64"),
builder.WithParamDescription("API version number"),
),
builder.WithResponse(http.StatusOK, struct {
ID string `json:"id"`
}{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
params := doc.Paths["/users/{user_id}"].Get.Parameters
fmt.Printf("user_id format: %s\n", params[0].Schema.Format)
fmt.Printf("version type: %s\n", params[1].Schema.Type)
fmt.Printf("version format: %s\n", params[1].Schema.Format)
}
Output: user_id format: uuid version type: integer version format: int64
Example (WithParameterConstraints) ¶
Example_withParameterConstraints demonstrates adding parameter constraints.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0")
// Add operation with constrained parameters
spec.AddOperation(http.MethodGet, "/pets",
builder.WithOperationID("listPets"),
// Numeric constraint: limit must be between 1 and 100, default 20
builder.WithQueryParam("limit", int32(0),
builder.WithParamDescription("Maximum number of pets to return"),
builder.WithParamMinimum(1),
builder.WithParamMaximum(100),
builder.WithParamDefault(20),
),
// Enum constraint: status must be one of the allowed values
builder.WithQueryParam("status", "",
builder.WithParamDescription("Filter by status"),
builder.WithParamEnum("available", "pending", "sold"),
builder.WithParamDefault("available"),
),
// String constraint: name must match pattern and length
builder.WithQueryParam("name", "",
builder.WithParamDescription("Filter by name"),
builder.WithParamMinLength(1),
builder.WithParamMaxLength(50),
builder.WithParamPattern("^[a-zA-Z]+$"),
),
builder.WithResponse(http.StatusOK, []Pet{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
params := doc.Paths["/pets"].Get.Parameters
fmt.Printf("Parameters: %d\n", len(params))
fmt.Printf("limit min: %.0f\n", *params[0].Schema.Minimum)
fmt.Printf("limit max: %.0f\n", *params[0].Schema.Maximum)
fmt.Printf("status enum count: %d\n", len(params[1].Schema.Enum))
fmt.Printf("name pattern: %s\n", params[2].Schema.Pattern)
}
Output: Parameters: 3 limit min: 1 limit max: 100 status enum count: 3 name pattern: ^[a-zA-Z]+$
Example (WithParameters) ¶
Example_withParameters demonstrates adding parameters.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/pets/{petId}",
builder.WithOperationID("getPet"),
builder.WithPathParam("petId", int64(0),
builder.WithParamDescription("The ID of the pet"),
),
builder.WithQueryParam("include", "",
builder.WithParamDescription("Include related resources"),
),
builder.WithResponse(http.StatusOK, Pet{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
paramCount := len(doc.Paths["/pets/{petId}"].Get.Parameters)
fmt.Printf("Parameters: %d\n", paramCount)
}
Output: Parameters: 2
Example (WithRawSchema) ¶
Example_withRawSchema demonstrates using raw schemas for binary data.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("File Download API").
SetVersion("1.0.0")
// Binary file download response
binarySchema := &parser.Schema{
Type: "string",
Format: "binary",
}
spec.AddOperation(http.MethodGet, "/download/{id}",
builder.WithOperationID("downloadFile"),
builder.WithPathParam("id", int64(0),
builder.WithParamDescription("File ID"),
),
builder.WithResponseRawSchema(http.StatusOK, "application/octet-stream", binarySchema,
builder.WithResponseDescription("Binary file content"),
builder.WithResponseHeader("Content-Disposition", &parser.Header{
Description: "Suggested filename",
Schema: &parser.Schema{Type: "string"},
}),
),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
resp := doc.Paths["/download/{id}"].Get.Responses.Codes["200"]
mediaType := resp.Content["application/octet-stream"]
fmt.Printf("Response content type: application/octet-stream\n")
fmt.Printf("Schema type: %s\n", mediaType.Schema.Type)
fmt.Printf("Schema format: %s\n", mediaType.Schema.Format)
fmt.Printf("Has Content-Disposition header: %v\n", resp.Headers["Content-Disposition"] != nil)
}
Output: Response content type: application/octet-stream Schema type: string Schema format: binary Has Content-Disposition header: true
Example (WithRequestBody) ¶
Example_withRequestBody demonstrates adding request bodies.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
// Pet represents a pet in the store.
type Pet struct {
ID int64 `json:"id" oas:"description=Unique pet identifier"`
Name string `json:"name" oas:"minLength=1,description=Pet name"`
Tag string `json:"tag,omitempty" oas:"description=Optional tag"`
CreatedAt time.Time `json:"created_at" oas:"readOnly=true"`
}
func main() {
type CreatePetRequest struct {
Name string `json:"name" oas:"minLength=1"`
Tag string `json:"tag,omitempty"`
}
spec := builder.New(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0").
AddOperation(http.MethodPost, "/pets",
builder.WithOperationID("createPet"),
builder.WithRequestBody("application/json", CreatePetRequest{},
builder.WithRequired(true),
builder.WithRequestDescription("Pet to create"),
),
builder.WithResponse(http.StatusCreated, Pet{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
hasRequestBody := doc.Paths["/pets"].Post.RequestBody != nil
fmt.Printf("Has request body: %v\n", hasRequestBody)
}
Output: Has request body: true
Example (WithSchemaFieldProcessor) ¶
Example_withSchemaFieldProcessor demonstrates custom struct tag processing. This allows libraries to support their own tag formats alongside the standard oas:"..." tags. Common use cases include:
- Migration support from other OpenAPI libraries with different tag formats
- Custom validation tag integration
- Framework integration with existing struct tag conventions
package main
import (
"fmt"
"log"
"net/http"
"reflect"
"strconv"
"strings"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
// Define a struct using standalone tags (legacy format from other libraries)
type LegacyUser struct {
Name string `json:"name" description:"User's full name"`
Status string `json:"status" enum:"active|inactive|pending"`
Age int `json:"age" minimum:"0" maximum:"150"`
}
// Create a processor that handles legacy standalone tags
legacyTagProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
// Skip if oas tag is present (already processed by oastools)
if field.Tag.Get("oas") != "" {
return schema
}
// Apply description tag
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
// Apply enum tag (pipe-separated values)
if enumStr := field.Tag.Get("enum"); enumStr != "" {
values := strings.Split(enumStr, "|")
schema.Enum = make([]any, len(values))
for i, v := range values {
schema.Enum[i] = strings.TrimSpace(v)
}
}
// Apply numeric constraints
if minStr := field.Tag.Get("minimum"); minStr != "" {
if min, err := strconv.ParseFloat(minStr, 64); err == nil {
schema.Minimum = &min
}
}
if maxStr := field.Tag.Get("maximum"); maxStr != "" {
if max, err := strconv.ParseFloat(maxStr, 64); err == nil {
schema.Maximum = &max
}
}
return schema
}
// Build specification with the custom processor
spec := builder.New(parser.OASVersion320,
builder.WithSchemaFieldProcessor(legacyTagProcessor),
).
SetTitle("Legacy API").
SetVersion("1.0.0").
AddOperation(http.MethodGet, "/users",
builder.WithResponse(http.StatusOK, LegacyUser{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
// Access the generated schema
userSchema := doc.Components.Schemas["builder_test.LegacyUser"]
nameSchema := userSchema.Properties["name"]
statusSchema := userSchema.Properties["status"]
ageSchema := userSchema.Properties["age"]
fmt.Printf("Name description: %s\n", nameSchema.Description)
fmt.Printf("Status enum: %v\n", statusSchema.Enum)
fmt.Printf("Age minimum: %.0f\n", *ageSchema.Minimum)
fmt.Printf("Age maximum: %.0f\n", *ageSchema.Maximum)
}
Output: Name description: User's full name Status enum: [active inactive pending] Age minimum: 0 Age maximum: 150
Example (WithSecurity) ¶
Example_withSecurity demonstrates security configuration.
package main
import (
"fmt"
"log"
"net/http"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("Secure API").
SetVersion("1.0.0").
AddAPIKeySecurityScheme("api_key", "header", "X-API-Key", "API key authentication").
AddHTTPSecurityScheme("bearer_auth", "bearer", "JWT", "Bearer token authentication").
SetSecurity(
builder.SecurityRequirement("api_key"),
builder.SecurityRequirement("bearer_auth"),
).
AddOperation(http.MethodGet, "/secure",
builder.WithOperationID("secureEndpoint"),
builder.WithResponse(http.StatusOK, struct{}{}),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
schemeCount := len(doc.Components.SecuritySchemes)
securityCount := len(doc.Security)
fmt.Printf("Security schemes: %d\n", schemeCount)
fmt.Printf("Global security requirements: %d\n", securityCount)
}
Output: Security schemes: 2 Global security requirements: 2
Example (WithServer) ¶
Example_withServer demonstrates adding servers.
package main
import (
"fmt"
"log"
"github.com/erraggy/oastools/builder"
"github.com/erraggy/oastools/parser"
)
func main() {
spec := builder.New(parser.OASVersion320).
SetTitle("My API").
SetVersion("1.0.0").
AddServer("https://api.example.com/v1",
builder.WithServerDescription("Production server"),
).
AddServer("https://staging.example.com/v1",
builder.WithServerDescription("Staging server"),
)
doc, err := spec.BuildOAS3()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Servers: %d\n", len(doc.Servers))
fmt.Printf("First server: %s\n", doc.Servers[0].URL)
}
Output: Servers: 2 First server: https://api.example.com/v1
Index ¶
- func MatchedPath(r *http.Request) string
- func PathParam(r *http.Request, name string) string
- func SecurityRequirement(schemeName string, scopes ...string) parser.SecurityRequirement
- type Builder
- func (b *Builder) AddAPIKeySecurityScheme(name string, in string, keyName string, description string) *Builder
- func (b *Builder) AddHTTPSecurityScheme(name string, scheme string, bearerFormat string, description string) *Builder
- func (b *Builder) AddOAuth2SecurityScheme(name string, flows *parser.OAuthFlows, description string) *Builder
- func (b *Builder) AddOpenIDConnectSecurityScheme(name string, openIDConnectURL string, description string) *Builder
- func (b *Builder) AddOperation(method, path string, opts ...OperationOption) *Builder
- func (b *Builder) AddParameter(name string, in string, paramName string, paramType any, opts ...ParamOption) *Builder
- func (b *Builder) AddResponse(name string, description string, responseType any, opts ...ResponseOption) *Builder
- func (b *Builder) AddSecurityScheme(name string, scheme *parser.SecurityScheme) *Builder
- func (b *Builder) AddServer(url string, opts ...ServerOption) *Builder
- func (b *Builder) AddTag(name string, opts ...TagOption) *Builder
- func (b *Builder) AddWebhook(name, method string, opts ...OperationOption) *Builder
- func (b *Builder) BuildOAS2() (*parser.OAS2Document, error)
- func (b *Builder) BuildOAS3() (*parser.OAS3Document, error)
- func (b *Builder) BuildResult() (*parser.ParseResult, error)
- func (b *Builder) DeduplicateSchemas() *Builder
- func (b *Builder) MarshalJSON() ([]byte, error)
- func (b *Builder) MarshalYAML() ([]byte, error)
- func (b *Builder) ParameterRef(name string) string
- func (b *Builder) RegisterType(v any) *parser.Schema
- func (b *Builder) RegisterTypeAs(name string, v any) *parser.Schema
- func (b *Builder) ResponseRef(name string) string
- func (b *Builder) SchemaRef(name string) string
- func (b *Builder) SetContact(contact *parser.Contact) *Builder
- func (b *Builder) SetDescription(desc string) *Builder
- func (b *Builder) SetExternalDocs(externalDocs *parser.ExternalDocs) *Builder
- func (b *Builder) SetInfo(info *parser.Info) *Builder
- func (b *Builder) SetLicense(license *parser.License) *Builder
- func (b *Builder) SetSecurity(requirements ...parser.SecurityRequirement) *Builder
- func (b *Builder) SetTermsOfService(url string) *Builder
- func (b *Builder) SetTitle(title string) *Builder
- func (b *Builder) SetVersion(version string) *Builder
- func (b *Builder) WriteFile(path string) error
- type BuilderError
- func NewDuplicateOperationIDError(operationID, method, path string, first *operationLocation) *BuilderError
- func NewDuplicateWebhookOperationIDError(operationID, webhookName, method string, first *operationLocation) *BuilderError
- func NewInvalidMethodError(method, path string) *BuilderError
- func NewParameterConstraintError(paramName, operationContext, field, message string) *BuilderError
- func NewSchemaError(schemaName, message string, cause error) *BuilderError
- func NewUnsupportedMethodError(method, path, minVersion string) *BuilderError
- type BuilderErrors
- type BuilderOption
- func WithGenericApplyBaseCasing(apply bool) BuilderOption
- func WithGenericIncludePackage(include bool) BuilderOption
- func WithGenericNaming(strategy GenericNamingStrategy) BuilderOption
- func WithGenericNamingConfig(config GenericNamingConfig) BuilderOption
- func WithGenericParamSeparator(sep string) BuilderOption
- func WithGenericSeparator(sep string) BuilderOption
- func WithSchemaFieldProcessor(fn SchemaFieldProcessor) BuilderOption
- func WithSchemaNameFunc(fn SchemaNameFunc) BuilderOption
- func WithSchemaNameTemplate(tmpl string) BuilderOption
- func WithSchemaNaming(strategy SchemaNamingStrategy) BuilderOption
- func WithSemanticDeduplication(enabled bool) BuilderOption
- type ComponentType
- type ConstraintError
- type ErrorHandler
- type GenericNamingConfig
- type GenericNamingStrategy
- type HandlerFunc
- type Middleware
- type OperationOption
- func WithConsumes(mimeTypes ...string) OperationOption
- func WithCookieParam(name string, paramType any, opts ...ParamOption) OperationOption
- func WithDefaultResponse(responseType any, opts ...ResponseOption) OperationOption
- func WithDeprecated(deprecated bool) OperationOption
- func WithDescription(desc string) OperationOption
- func WithFileParam(name string, opts ...ParamOption) OperationOption
- func WithFormParam(name string, paramType any, opts ...ParamOption) OperationOption
- func WithHandler(handler HandlerFunc) OperationOption
- func WithHandlerFunc(handler http.HandlerFunc) OperationOption
- func WithHeaderParam(name string, paramType any, opts ...ParamOption) OperationOption
- func WithNoSecurity() OperationOption
- func WithOperationExtension(key string, value any) OperationOption
- func WithOperationID(id string) OperationOption
- func WithParameter(param *parser.Parameter) OperationOption
- func WithParameterRef(ref string) OperationOption
- func WithPathParam(name string, paramType any, opts ...ParamOption) OperationOption
- func WithProduces(mimeTypes ...string) OperationOption
- func WithQueryParam(name string, paramType any, opts ...ParamOption) OperationOption
- func WithRequestBody(contentType string, bodyType any, opts ...RequestBodyOption) OperationOption
- func WithRequestBodyContentTypes(contentTypes []string, bodyType any, opts ...RequestBodyOption) OperationOption
- func WithRequestBodyRawSchema(contentType string, schema *parser.Schema, opts ...RequestBodyOption) OperationOption
- func WithResponse(statusCode int, responseType any, opts ...ResponseOption) OperationOption
- func WithResponseContentTypes(statusCode int, contentTypes []string, responseType any, ...) OperationOption
- func WithResponseRawSchema(statusCode int, contentType string, schema *parser.Schema, ...) OperationOption
- func WithResponseRef(statusCode int, ref string) OperationOption
- func WithSecurity(requirements ...parser.SecurityRequirement) OperationOption
- func WithSummary(summary string) OperationOption
- func WithTags(tags ...string) OperationOption
- type ParamOption
- func WithParamAllowEmptyValue(allow bool) ParamOption
- func WithParamCollectionFormat(format string) ParamOption
- func WithParamDefault(value any) ParamOption
- func WithParamDeprecated(deprecated bool) ParamOption
- func WithParamDescription(desc string) ParamOption
- func WithParamEnum(values ...any) ParamOption
- func WithParamExample(example any) ParamOption
- func WithParamExclusiveMaximum(exclusive bool) ParamOption
- func WithParamExclusiveMinimum(exclusive bool) ParamOption
- func WithParamExtension(key string, value any) ParamOption
- func WithParamFormat(format string) ParamOption
- func WithParamMaxItems(max int) ParamOption
- func WithParamMaxLength(max int) ParamOption
- func WithParamMaximum(max float64) ParamOption
- func WithParamMinItems(min int) ParamOption
- func WithParamMinLength(min int) ParamOption
- func WithParamMinimum(min float64) ParamOption
- func WithParamMultipleOf(value float64) ParamOption
- func WithParamPattern(pattern string) ParamOption
- func WithParamRequired(required bool) ParamOption
- func WithParamSchema(schema *parser.Schema) ParamOption
- func WithParamType(typeName string) ParamOption
- func WithParamUniqueItems(unique bool) ParamOption
- type Request
- type RequestBodyOption
- type Response
- func Error(status int, message string) Response
- func ErrorWithDetails(status int, message string, details any) Response
- func JSON(status int, body any) Response
- func NoContent() Response
- func Redirect(status int, location string) Response
- func Stream(status int, contentType string, reader io.Reader) Response
- type ResponseBuilder
- func (b *ResponseBuilder) Binary(contentType string, data []byte) Response
- func (b *ResponseBuilder) Body() any
- func (b *ResponseBuilder) Header(key, value string) *ResponseBuilder
- func (b *ResponseBuilder) Headers() http.Header
- func (b *ResponseBuilder) JSON(body any) Response
- func (b *ResponseBuilder) StatusCode() int
- func (b *ResponseBuilder) Text(body string) Response
- func (b *ResponseBuilder) WriteTo(w http.ResponseWriter) error
- func (b *ResponseBuilder) XML(body any) Response
- type ResponseOption
- func WithResponseContentType(contentType string) ResponseOption
- func WithResponseDescription(desc string) ResponseOption
- func WithResponseExample(example any) ResponseOption
- func WithResponseExtension(key string, value any) ResponseOption
- func WithResponseHeader(name string, header *parser.Header) ResponseOption
- type RouterStrategy
- type SchemaFieldProcessor
- type SchemaNameContext
- type SchemaNameFunc
- type SchemaNamingStrategy
- type ServerBuilder
- func (s *ServerBuilder) AddOperation(method, path string, opts ...OperationOption) *ServerBuilder
- func (s *ServerBuilder) AddSecurityScheme(name string, scheme *parser.SecurityScheme) *ServerBuilder
- func (s *ServerBuilder) AddServer(url string, opts ...ServerOption) *ServerBuilder
- func (s *ServerBuilder) AddTag(name string, opts ...TagOption) *ServerBuilder
- func (s *ServerBuilder) BuildServer() (*ServerResult, error)
- func (s *ServerBuilder) Handle(method, path string, handler HandlerFunc) *ServerBuilder
- func (s *ServerBuilder) HandleFunc(method, path string, handler http.HandlerFunc) *ServerBuilder
- func (s *ServerBuilder) MustBuildServer() *ServerResult
- func (s *ServerBuilder) SetDescription(desc string) *ServerBuilder
- func (s *ServerBuilder) SetSecurity(requirements ...parser.SecurityRequirement) *ServerBuilder
- func (s *ServerBuilder) SetTitle(title string) *ServerBuilder
- func (s *ServerBuilder) SetVersion(version string) *ServerBuilder
- func (s *ServerBuilder) Use(mw ...Middleware) *ServerBuilder
- type ServerBuilderOption
- func WithErrorHandler(handler ErrorHandler) ServerBuilderOption
- func WithMethodNotAllowedHandler(handler http.Handler) ServerBuilderOption
- func WithNotFoundHandler(handler http.Handler) ServerBuilderOption
- func WithRecovery() ServerBuilderOption
- func WithRequestLogging(logger func(method, path string, status int, duration time.Duration)) ServerBuilderOption
- func WithRouter(strategy RouterStrategy) ServerBuilderOption
- func WithStdlibRouter() ServerBuilderOption
- func WithValidationConfig(validationCfg ValidationConfig) ServerBuilderOption
- func WithoutValidation() ServerBuilderOption
- type ServerOption
- type ServerResult
- type ServerTest
- func (t *ServerTest) Delete(path string) *httptest.ResponseRecorder
- func (t *ServerTest) Execute(req *TestRequest) *httptest.ResponseRecorder
- func (t *ServerTest) GetJSON(path string, target any) (*httptest.ResponseRecorder, error)
- func (t *ServerTest) PostJSON(path string, body any, target any) (*httptest.ResponseRecorder, error)
- func (t *ServerTest) PutJSON(path string, body any, target any) (*httptest.ResponseRecorder, error)
- func (t *ServerTest) Request(method, path string) *TestRequest
- type ServerVariableOption
- type TagOption
- type TestRequest
- func (r *TestRequest) Body(contentType string, body io.Reader) *TestRequest
- func (r *TestRequest) Build() *http.Request
- func (r *TestRequest) Execute(handler http.Handler) *httptest.ResponseRecorder
- func (r *TestRequest) Header(key, value string) *TestRequest
- func (r *TestRequest) JSONBody(body any) *TestRequest
- func (r *TestRequest) Query(key, value string) *TestRequest
- type ValidationConfig
- type ValidationErrorHandler
Examples ¶
- Package
- Package (CompleteAPI)
- Package (ComposeSchemaFieldProcessors)
- Package (FromDocument)
- Package (GenericNamingConfig)
- Package (SchemaGeneration)
- Package (SchemaNamingCustomFunc)
- Package (SchemaNamingPascalCase)
- Package (SchemaNamingTemplate)
- Package (SemanticDeduplication)
- Package (ServerBuilder)
- Package (ServerBuilderCRUD)
- Package (ServerBuilderFromBuilder)
- Package (ServerBuilderMiddleware)
- Package (ServerBuilderResponseBuilder)
- Package (ServerBuilderResponses)
- Package (ServerBuilderTesting)
- Package (ServerBuilderWithValidation)
- Package (WithComplexRawSchema)
- Package (WithFileUpload)
- Package (WithFormParameters)
- Package (WithParamTypeFormatOverride)
- Package (WithParameterConstraints)
- Package (WithParameters)
- Package (WithRawSchema)
- Package (WithRequestBody)
- Package (WithSchemaFieldProcessor)
- Package (WithSecurity)
- Package (WithServer)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MatchedPath ¶ added in v1.34.0
MatchedPath returns the matched path template from the request context.
Example:
template := builder.MatchedPath(r) // e.g., "/pets/{petId}"
func PathParam ¶ added in v1.34.0
PathParam extracts a path parameter from the request context. This is a package-level function for convenience.
Example:
petID := builder.PathParam(r, "petId")
func SecurityRequirement ¶
func SecurityRequirement(schemeName string, scopes ...string) parser.SecurityRequirement
SecurityRequirement creates a security requirement for use with SetSecurity or WithSecurity.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder is the main entry point for constructing OAS documents. It maintains internal state for accumulated components and reflection cache.
Concurrency: Builder instances are not safe for concurrent use. Create separate Builder instances for concurrent operations.
func FromDocument ¶
func FromDocument(doc *parser.OAS3Document) *Builder
FromDocument creates a builder from an existing OAS3Document. This allows modifying an existing document by adding operations.
For OAS 2.0 documents, use FromOAS2Document instead.
func FromOAS2Document ¶
func FromOAS2Document(doc *parser.OAS2Document) *Builder
FromOAS2Document creates a builder from an existing OAS2Document (Swagger 2.0). This allows modifying an existing document by adding operations.
For OAS 3.x documents, use FromDocument instead.
func New ¶
func New(version parser.OASVersion, opts ...BuilderOption) *Builder
New creates a new Builder instance for the specified OAS version. Use BuildOAS2() for OAS 2.0 (Swagger) or BuildOAS3() for OAS 3.x documents.
Options can be provided to customize schema naming:
// Use PascalCase naming (e.g., "ModelsUser" instead of "models.User")
spec := builder.New(parser.OASVersion320,
builder.WithSchemaNaming(builder.SchemaNamingPascalCase),
)
The builder does not perform OAS specification validation. Use the validator package to validate built documents.
Example:
spec := builder.New(parser.OASVersion320).
SetTitle("My API").
SetVersion("1.0.0")
doc, err := spec.BuildOAS3()
func NewWithInfo ¶
func NewWithInfo(version parser.OASVersion, info *parser.Info) *Builder
NewWithInfo creates a Builder with pre-configured Info.
Example:
info := &parser.Info{Title: "My API", Version: "1.0.0"}
spec := builder.NewWithInfo(parser.OASVersion320, info)
func (*Builder) AddAPIKeySecurityScheme ¶
func (b *Builder) AddAPIKeySecurityScheme(name string, in string, keyName string, description string) *Builder
AddAPIKeySecurityScheme adds an API key security scheme.
func (*Builder) AddHTTPSecurityScheme ¶
func (b *Builder) AddHTTPSecurityScheme(name string, scheme string, bearerFormat string, description string) *Builder
AddHTTPSecurityScheme adds an HTTP security scheme (Basic, Bearer, etc.).
func (*Builder) AddOAuth2SecurityScheme ¶
func (b *Builder) AddOAuth2SecurityScheme(name string, flows *parser.OAuthFlows, description string) *Builder
AddOAuth2SecurityScheme adds an OAuth2 security scheme.
func (*Builder) AddOpenIDConnectSecurityScheme ¶
func (b *Builder) AddOpenIDConnectSecurityScheme(name string, openIDConnectURL string, description string) *Builder
AddOpenIDConnectSecurityScheme adds an OpenID Connect security scheme.
func (*Builder) AddOperation ¶
func (b *Builder) AddOperation(method, path string, opts ...OperationOption) *Builder
AddOperation adds an API operation to the specification. Go types passed to options are automatically converted to schemas via reflection.
Note: OpenAPI requires at least one response per operation. If no responses are defined, the resulting spec will fail OAS validation. Use WithResponse() or WithDefaultResponse() to add responses. The builder package does not perform OAS specification validation; use the validator package to validate built documents.
func (*Builder) AddParameter ¶
func (b *Builder) AddParameter(name string, in string, paramName string, paramType any, opts ...ParamOption) *Builder
AddParameter adds a reusable parameter to components.parameters (OAS 3.x) or parameters (OAS 2.0).
Constraint validation is performed and any errors are accumulated in the builder. Use BuildOAS2() or BuildOAS3() to check for accumulated errors.
func (*Builder) AddResponse ¶
func (b *Builder) AddResponse(name string, description string, responseType any, opts ...ResponseOption) *Builder
AddResponse adds a reusable response to components.responses (OAS 3.x) or responses (OAS 2.0). Use WithResponseContentType to specify a content type other than "application/json".
func (*Builder) AddSecurityScheme ¶
func (b *Builder) AddSecurityScheme(name string, scheme *parser.SecurityScheme) *Builder
AddSecurityScheme adds a security scheme to components.securitySchemes.
func (*Builder) AddServer ¶
func (b *Builder) AddServer(url string, opts ...ServerOption) *Builder
AddServer adds a server to the specification.
func (*Builder) AddWebhook ¶
func (b *Builder) AddWebhook(name, method string, opts ...OperationOption) *Builder
AddWebhook adds a webhook to the specification (OAS 3.1+ only). Webhooks are callbacks that are triggered by the API provider. Returns an error during Build if used with OAS versions earlier than 3.1.
Example:
spec.AddWebhook("newUser", http.MethodPost,
builder.WithResponse(http.StatusOK, UserCreatedEvent{}),
)
func (*Builder) BuildOAS2 ¶
func (b *Builder) BuildOAS2() (*parser.OAS2Document, error)
BuildOAS2 creates an OAS 2.0 (Swagger) document. Returns an error if the builder was created with an OAS 3.x version, or if required fields are missing.
The builder does not perform OAS specification validation. Use the validator package to validate built documents.
Example:
spec := builder.New(parser.OASVersion20).
SetTitle("My API").
SetVersion("1.0.0")
doc, err := spec.BuildOAS2()
// doc is *parser.OAS2Document - no type assertion needed
func (*Builder) BuildOAS3 ¶
func (b *Builder) BuildOAS3() (*parser.OAS3Document, error)
BuildOAS3 creates an OAS 3.x document. Returns an error if the builder was created with OAS 2.0 version, or if required fields are missing.
The builder does not perform OAS specification validation. Use the validator package to validate built documents.
Example:
spec := builder.New(parser.OASVersion320).
SetTitle("My API").
SetVersion("1.0.0")
doc, err := spec.BuildOAS3()
// doc is *parser.OAS3Document - no type assertion needed
func (*Builder) BuildResult ¶
func (b *Builder) BuildResult() (*parser.ParseResult, error)
BuildResult creates a ParseResult for compatibility with other packages. This is useful for validating the built document with the validator package.
The builder does not perform OAS specification validation. Use the validator package to validate built documents:
result, err := spec.BuildResult()
if err != nil { return err }
valResult, err := validator.ValidateParsed(result)
func (*Builder) DeduplicateSchemas ¶ added in v1.26.0
DeduplicateSchemas identifies semantically identical schemas and consolidates them to a single canonical schema. This method should be called after all schemas have been added but before Build*() methods.
Schemas are considered semantically identical if they have the same structural properties (type, format, properties, constraints, etc.), ignoring metadata fields like title, description, and examples.
The canonical schema name is selected alphabetically. For example, if "Address" and "Location" schemas are identical, "Address" becomes canonical and all references to "Location" are rewritten to point to "Address".
Returns the Builder for method chaining.
Note: This method is automatically called by Build*() methods when WithSemanticDeduplication(true) is set. Call it manually only if you need to inspect schemaAliases before building.
func (*Builder) MarshalJSON ¶
MarshalJSON returns the document as JSON bytes.
func (*Builder) MarshalYAML ¶
MarshalYAML returns the document as YAML bytes.
func (*Builder) ParameterRef ¶
ParameterRef returns a reference to a named parameter. This method returns the version-appropriate ref path.
func (*Builder) RegisterType ¶
RegisterType registers a Go type and returns a $ref to it. The schema is automatically generated via reflection and added to components.schemas.
func (*Builder) RegisterTypeAs ¶
RegisterTypeAs registers a Go type with a custom schema name.
func (*Builder) ResponseRef ¶
ResponseRef returns a reference to a named response. This method returns the version-appropriate ref path.
func (*Builder) SchemaRef ¶
SchemaRef returns a reference string to a named schema. This method returns the version-appropriate ref path:
- OAS 2.0: "#/definitions/{name}"
- OAS 3.x: "#/components/schemas/{name}"
func (*Builder) SetContact ¶
SetContact sets the contact information in the Info object.
func (*Builder) SetDescription ¶
SetDescription sets the description in the Info object.
func (*Builder) SetExternalDocs ¶
func (b *Builder) SetExternalDocs(externalDocs *parser.ExternalDocs) *Builder
SetExternalDocs sets the external documentation for the document. This is used for providing additional documentation at the document level.
func (*Builder) SetLicense ¶
SetLicense sets the license information in the Info object.
func (*Builder) SetSecurity ¶
func (b *Builder) SetSecurity(requirements ...parser.SecurityRequirement) *Builder
SetSecurity sets the global security requirements.
func (*Builder) SetTermsOfService ¶
SetTermsOfService sets the terms of service URL in the Info object.
func (*Builder) SetVersion ¶
SetVersion sets the version in the Info object. Note: This is the API version, not the OpenAPI specification version.
type BuilderError ¶ added in v1.35.0
type BuilderError struct {
// Component is the type of component where the error occurred.
Component ComponentType
// Method is the HTTP method (for operation/webhook errors).
Method string
// Path is the API path (for operation errors) or webhook name.
Path string
// OperationID is the operation identifier (if applicable).
OperationID string
// Field is the specific field with the error (e.g., "minimum").
Field string
// Message describes the error.
Message string
// Context provides additional details (e.g., conflicting values).
Context map[string]any
// FirstOccurrence tracks where a duplicate was first defined.
FirstOccurrence *operationLocation
// Cause is the underlying error, if any.
Cause error
}
BuilderError represents a structured error from the builder package. It provides detailed context about where and why an error occurred during the fluent API building process.
func NewDuplicateOperationIDError ¶ added in v1.35.0
func NewDuplicateOperationIDError(operationID, method, path string, first *operationLocation) *BuilderError
NewDuplicateOperationIDError creates an error for duplicate operation IDs.
func NewDuplicateWebhookOperationIDError ¶ added in v1.35.0
func NewDuplicateWebhookOperationIDError(operationID, webhookName, method string, first *operationLocation) *BuilderError
NewDuplicateWebhookOperationIDError creates an error for duplicate operation IDs in webhooks.
func NewInvalidMethodError ¶ added in v1.35.0
func NewInvalidMethodError(method, path string) *BuilderError
NewInvalidMethodError creates an error for invalid/unknown HTTP methods.
func NewParameterConstraintError ¶ added in v1.35.0
func NewParameterConstraintError(paramName, operationContext, field, message string) *BuilderError
NewParameterConstraintError creates an error for parameter constraint violations.
func NewSchemaError ¶ added in v1.35.0
func NewSchemaError(schemaName, message string, cause error) *BuilderError
NewSchemaError creates an error for schema-related issues.
func NewUnsupportedMethodError ¶ added in v1.35.0
func NewUnsupportedMethodError(method, path, minVersion string) *BuilderError
NewUnsupportedMethodError creates an error for unsupported HTTP methods.
func (*BuilderError) Error ¶ added in v1.35.0
func (e *BuilderError) Error() string
Error implements the error interface with a detailed, formatted message.
func (*BuilderError) HasLocation ¶ added in v1.35.0
func (e *BuilderError) HasLocation() bool
HasLocation returns true if this error has location context. BuilderError uses component/method/path instead of line/column.
func (*BuilderError) Is ¶ added in v1.35.0
func (e *BuilderError) Is(target error) bool
Is reports whether target matches this error type. All BuilderErrors are classified as ErrConfig errors, enabling callers to use errors.Is(err, oaserrors.ErrConfig) to detect builder configuration issues. This includes validation errors, duplicate detection, and unsupported features.
func (*BuilderError) Location ¶ added in v1.35.0
func (e *BuilderError) Location() string
Location returns a descriptive location string.
func (*BuilderError) Unwrap ¶ added in v1.35.0
func (e *BuilderError) Unwrap() error
Unwrap returns the underlying error for errors.Is/As support.
type BuilderErrors ¶ added in v1.35.0
type BuilderErrors []*BuilderError
BuilderErrors is a collection of BuilderError with formatting support.
func (BuilderErrors) Error ¶ added in v1.35.0
func (errs BuilderErrors) Error() string
Error implements the error interface with a formatted multi-error message.
func (BuilderErrors) Unwrap ¶ added in v1.35.0
func (errs BuilderErrors) Unwrap() []error
Unwrap returns the errors for Go 1.20+ error wrapping semantics, enabling errors.Is and errors.As to work with multiple wrapped errors.
type BuilderOption ¶ added in v1.25.0
type BuilderOption func(*builderConfig)
BuilderOption configures a Builder instance. Options are applied when creating a new Builder with New().
func WithGenericApplyBaseCasing ¶ added in v1.25.0
func WithGenericApplyBaseCasing(apply bool) BuilderOption
WithGenericApplyBaseCasing applies the base naming strategy to type parameters. When true with SchemaNamingPascalCase, Response[user_profile] becomes ResponseOfUserProfile. Default is false.
func WithGenericIncludePackage ¶ added in v1.25.0
func WithGenericIncludePackage(include bool) BuilderOption
WithGenericIncludePackage includes package names in generic type parameters. When true, Response[models.User] becomes Response_models_User_. Default is false.
func WithGenericNaming ¶ added in v1.25.0
func WithGenericNaming(strategy GenericNamingStrategy) BuilderOption
WithGenericNaming sets the strategy for handling generic type names. The default is GenericNamingUnderscore which produces "Response_User_" format.
Available strategies:
- GenericNamingUnderscore: "Response_User_" (default)
- GenericNamingOf: "ResponseOfUser"
- GenericNamingFor: "ResponseForUser"
- GenericNamingAngleBrackets: "Response<User>" (URI-encoded in $ref)
- GenericNamingFlattened: "ResponseUser"
func WithGenericNamingConfig ¶ added in v1.25.0
func WithGenericNamingConfig(config GenericNamingConfig) BuilderOption
WithGenericNamingConfig provides fine-grained control over generic type naming. This replaces any previous generic naming settings.
Example:
WithGenericNamingConfig(builder.GenericNamingConfig{
Strategy: builder.GenericNamingOf,
ParamSeparator: "And",
ApplyBaseCasing: true,
})
func WithGenericParamSeparator ¶ added in v1.25.0
func WithGenericParamSeparator(sep string) BuilderOption
WithGenericParamSeparator sets the separator between multiple type parameters. Default is "_".
Example:
WithGenericParamSeparator("And")
// Map[string,int] with GenericNamingOf becomes MapOfStringAndOfInt
func WithGenericSeparator ¶ added in v1.25.0
func WithGenericSeparator(sep string) BuilderOption
WithGenericSeparator sets the separator used for generic type parameters. Only applies to GenericNamingUnderscore strategy. Default is "_".
Example:
WithGenericSeparator("__")
// Response[User] becomes Response__User__
func WithSchemaFieldProcessor ¶ added in v1.36.0
func WithSchemaFieldProcessor(fn SchemaFieldProcessor) BuilderOption
WithSchemaFieldProcessor sets a custom function for processing struct field tags. This enables libraries to support custom tag formats alongside the standard oas:"..." tags.
The processor is called for each struct field after the base schema is generated and after any oas:"..." tags are applied. It receives the generated schema and the reflect.StructField, allowing access to all struct tags.
Example - supporting legacy standalone tags:
spec := builder.New(parser.OASVersion320,
builder.WithSchemaFieldProcessor(func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
// Skip if oas tag is present (already processed)
if field.Tag.Get("oas") != "" {
return schema
}
// Apply legacy description tag
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
// Apply legacy enum tag
if enumStr := field.Tag.Get("enum"); enumStr != "" {
values := strings.Split(enumStr, "|")
schema.Enum = make([]any, len(values))
for i, v := range values {
schema.Enum[i] = strings.TrimSpace(v)
}
}
return schema
}),
)
Use cases:
- Migration support from other OpenAPI libraries with different tag formats
- Custom validation tag integration (e.g., reading from validator tags)
- Documentation generators pulling from godoc-style comments or other sources
- Framework integration with existing struct tag conventions
func WithSchemaNameFunc ¶ added in v1.25.0
func WithSchemaNameFunc(fn SchemaNameFunc) BuilderOption
WithSchemaNameFunc sets a custom function for schema naming. Provides maximum flexibility for programmatic naming logic. The function receives SchemaNameContext and returns the schema name.
Example:
WithSchemaNameFunc(func(ctx builder.SchemaNameContext) string {
if ctx.IsAnonymous {
return "AnonymousType"
}
return strings.ToUpper(ctx.Package) + "_" + ctx.Type
})
Setting a custom function clears any previously set template.
func WithSchemaNameTemplate ¶ added in v1.25.0
func WithSchemaNameTemplate(tmpl string) BuilderOption
WithSchemaNameTemplate sets a custom Go text/template for schema naming. Template receives SchemaNameContext with type metadata. Template parse errors are returned by Build*() methods.
Available template functions: pascal, camel, snake, kebab, upper, lower, title, sanitize, trimPrefix, trimSuffix, replace, join.
Available context fields:
- .Type: Go type name without package (e.g., "User", "Response[T]")
- .TypeSanitized: Type with generic brackets replaced per GenericNamingStrategy
- .TypeBase: Base type name without generic parameters (e.g., "Response")
- .Package: Package base name (e.g., "models")
- .PackagePath: Full import path (e.g., "github.com/org/models")
- .PackagePathSanitized: PackagePath with slashes replaced
- .IsGeneric: Whether the type has type parameters
- .GenericParams: Type parameter names if IsGeneric is true
- .GenericParamsSanitized: Sanitized type parameter names
- .GenericSuffix: Formatted generic parameters portion
- .IsAnonymous: Whether this is an anonymous struct type
- .IsPointer: Whether the original type was a pointer
- .Kind: The reflect.Kind as a string
Example:
WithSchemaNameTemplate(`{{pascal .Package}}{{pascal .Type}}`)
Template parse errors are returned by BuildOAS3() or BuildOAS2(). If template execution fails at runtime for a specific type (e.g., due to accessing an invalid field), the naming falls back to the default "package.TypeName" format silently. Ensure templates are tested with representative types to avoid unexpected fallback behavior.
Setting a template clears any previously set custom function.
func WithSchemaNaming ¶ added in v1.25.0
func WithSchemaNaming(strategy SchemaNamingStrategy) BuilderOption
WithSchemaNaming sets a built-in schema naming strategy. The default is SchemaNamingDefault which produces "package.TypeName" format.
Available strategies:
- SchemaNamingDefault: "package.TypeName" (e.g., models.User)
- SchemaNamingPascalCase: "PackageTypeName" (e.g., ModelsUser)
- SchemaNamingCamelCase: "packageTypeName" (e.g., modelsUser)
- SchemaNamingSnakeCase: "package_type_name" (e.g., models_user)
- SchemaNamingKebabCase: "package-type-name" (e.g., models-user)
- SchemaNamingTypeOnly: "TypeName" (e.g., User) - may cause conflicts
- SchemaNamingFullPath: "full_path_TypeName" (e.g., github.com_org_models_User)
Setting a naming strategy clears any previously set template or custom function.
func WithSemanticDeduplication ¶ added in v1.26.0
func WithSemanticDeduplication(enabled bool) BuilderOption
WithSemanticDeduplication enables semantic schema deduplication. When enabled, the builder identifies schemas that are structurally identical and consolidates them to a single canonical schema. All references to duplicate schemas are rewritten to point to the canonical schema.
The canonical schema name is selected alphabetically (e.g., if "Address" and "Location" are identical, "Address" becomes canonical).
This option reduces document size when multiple types converge to the same structure. It is disabled by default.
Example:
spec := builder.New(parser.OASVersion320,
builder.WithSemanticDeduplication(true),
)
type ComponentType ¶ added in v1.35.0
type ComponentType string
ComponentType identifies the type of component where an error occurred.
const ( // ComponentOperation indicates an error in an operation definition. ComponentOperation ComponentType = "operation" // ComponentWebhook indicates an error in a webhook definition. ComponentWebhook ComponentType = "webhook" // ComponentParameter indicates an error in a parameter definition. ComponentParameter ComponentType = "parameter" // ComponentSchema indicates an error in a schema definition. ComponentSchema ComponentType = "schema" // ComponentRequestBody indicates an error in a request body definition. ComponentRequestBody ComponentType = "request_body" // ComponentResponse indicates an error in a response definition. ComponentResponse ComponentType = "response" // ComponentSecurityScheme indicates an error in a security scheme. ComponentSecurityScheme ComponentType = "security_scheme" // ComponentServer indicates an error in a server definition. ComponentServer ComponentType = "server" )
type ConstraintError ¶ added in v1.13.1
type ConstraintError struct {
// Field is the constraint field that failed (e.g., "minimum", "pattern").
Field string
// Message describes the constraint violation.
Message string
// ParamName is the parameter name where this constraint was applied (optional).
ParamName string
// OperationContext describes the operation context (e.g., "POST /users").
OperationContext string
}
ConstraintError represents an invalid constraint configuration. It provides context about which field failed validation and why.
func (*ConstraintError) Error ¶ added in v1.13.1
func (e *ConstraintError) Error() string
Error implements the error interface.
func (*ConstraintError) HasLocation ¶ added in v1.35.0
func (e *ConstraintError) HasLocation() bool
HasLocation returns true if this error has location context.
func (*ConstraintError) Is ¶ added in v1.35.0
func (e *ConstraintError) Is(target error) bool
Is reports whether target matches this error type. ConstraintError matches oaserrors.ErrConfig for programmatic error handling.
func (*ConstraintError) Location ¶ added in v1.35.0
func (e *ConstraintError) Location() string
Location returns a descriptive location string.
func (*ConstraintError) Unwrap ¶ added in v1.35.0
func (e *ConstraintError) Unwrap() error
Unwrap returns nil as ConstraintError has no underlying cause. This method exists for interface consistency with BuilderError.
type ErrorHandler ¶ added in v1.34.0
type ErrorHandler func(w http.ResponseWriter, r *http.Request, err error)
ErrorHandler handles errors during request processing.
type GenericNamingConfig ¶ added in v1.25.0
type GenericNamingConfig struct {
// Strategy is the primary generic naming approach.
Strategy GenericNamingStrategy
// Separator is used between base type and parameters.
// Only applies to GenericNamingUnderscore strategy.
// Default: "_"
Separator string
// ParamSeparator is used between multiple type parameters.
// Example with ParamSeparator="_": Map[string,int] -> Map_string_int
// Example with ParamSeparator="And": Map[string,int] -> MapOfStringAndOfInt
// Default: "_"
ParamSeparator string
// IncludePackage includes the type parameter's package in the name.
// Example: Response[models.User] -> Response_models_User (true)
// Example: Response[models.User] -> Response_User (false, default)
IncludePackage bool
// ApplyBaseCasing applies the base naming strategy to type parameters.
// Example with SchemaNamingPascalCase: Response[user_profile] -> ResponseOfUserProfile
ApplyBaseCasing bool
}
GenericNamingConfig provides fine-grained control over generic type naming.
func DefaultGenericNamingConfig ¶ added in v1.25.0
func DefaultGenericNamingConfig() GenericNamingConfig
DefaultGenericNamingConfig returns the default generic naming configuration. This matches the current behavior where brackets are replaced with underscores.
type GenericNamingStrategy ¶ added in v1.25.0
type GenericNamingStrategy int
GenericNamingStrategy defines how generic type parameters are formatted in schema names.
const ( // GenericNamingUnderscore replaces brackets with underscores (default behavior). // Example: Response[User] -> Response_User_ GenericNamingUnderscore GenericNamingStrategy = iota // GenericNamingOf uses "Of" separator between base type and parameters. // Example: Response[User] -> ResponseOfUser GenericNamingOf // GenericNamingFor uses "For" separator. // Example: Response[User] -> ResponseForUser GenericNamingFor // GenericNamingAngleBrackets uses angle brackets (URI-encoded in $ref). // Example: Response[User] -> Response<User> // Note: Produces Response%3CUser%3E in $ref URIs. GenericNamingAngleBrackets // GenericNamingFlattened removes brackets entirely. // Example: Response[User] -> ResponseUser GenericNamingFlattened )
type HandlerFunc ¶ added in v1.34.0
HandlerFunc is the signature for operation handlers. The Request contains validated parameters and the raw http.Request. The Response interface allows type-safe response construction.
func ErrorStubHandler ¶ added in v1.34.0
func ErrorStubHandler(status int, message string) HandlerFunc
ErrorStubHandler creates a handler that returns an error response.
Example:
srv.Handle(http.MethodDelete, "/pets/{petId}", builder.ErrorStubHandler(http.StatusNotFound, "pet not found"))
func StubHandler ¶ added in v1.34.0
func StubHandler(response Response) HandlerFunc
StubHandler creates a handler that returns a fixed response.
Example:
srv.Handle(http.MethodGet, "/pets", builder.StubHandler(builder.JSON(http.StatusOK, pets)))
func StubHandlerFunc ¶ added in v1.34.0
func StubHandlerFunc(fn func(req *Request) Response) HandlerFunc
StubHandlerFunc creates a handler that calls a function. Useful for asserting request contents in tests.
Example:
srv.Handle(http.MethodGet, "/pets/{petId}", builder.StubHandlerFunc(func(req *builder.Request) builder.Response {
petID := req.PathParams["petId"]
// assertions on petID
return builder.JSON(http.StatusOK, pet)
}))
type Middleware ¶ added in v1.34.0
Middleware wraps handlers with additional behavior.
type OperationOption ¶
type OperationOption func(*operationConfig)
OperationOption configures an operation.
func WithConsumes ¶ added in v1.30.0
func WithConsumes(mimeTypes ...string) OperationOption
WithConsumes sets the consumes MIME types for the operation. This is only applicable to OAS 2.0 specifications. For OAS 3.x, use WithRequestBodyContentTypes instead to specify multiple content types.
Example:
builder.AddOperation("POST", "/users",
builder.WithConsumes("application/json", "application/xml"),
builder.WithRequestBody("application/json", User{}),
)
func WithCookieParam ¶
func WithCookieParam(name string, paramType any, opts ...ParamOption) OperationOption
WithCookieParam adds a cookie parameter to the operation.
func WithDefaultResponse ¶
func WithDefaultResponse(responseType any, opts ...ResponseOption) OperationOption
WithDefaultResponse sets the default response for the operation. Use WithResponseContentType to specify a content type other than "application/json".
func WithDeprecated ¶
func WithDeprecated(deprecated bool) OperationOption
WithDeprecated marks the operation as deprecated.
func WithDescription ¶
func WithDescription(desc string) OperationOption
WithDescription sets the operation description.
func WithFileParam ¶ added in v1.15.0
func WithFileParam(name string, opts ...ParamOption) OperationOption
WithFileParam adds a file upload parameter to the operation. This is primarily for OAS 2.0 file uploads using formData parameters with type="file". For OAS 3.x, it automatically creates a multipart/form-data request body with binary format.
Note: Parameter constraints (minLength, maxLength, pattern, etc.) are not applicable to file parameters and will be ignored. Only description, required, and deprecated options are meaningful for file uploads.
Example (OAS 2.0):
WithFileParam("file", WithParamDescription("File to upload"), WithParamRequired(true))
Example (OAS 3.x):
// Automatically generates multipart/form-data request body:
WithFileParam("file", WithParamDescription("File to upload"), WithParamRequired(true))
func WithFormParam ¶ added in v1.14.0
func WithFormParam(name string, paramType any, opts ...ParamOption) OperationOption
WithFormParam adds a form parameter to the operation. The handling differs based on OAS version:
- OAS 2.0: Adds a parameter with in="formData"
- OAS 3.x: Adds to request body with content-type application/x-www-form-urlencoded
Form parameters support all standard parameter options including constraints, description, required flag, default values, and format specifications.
func WithHandler ¶ added in v1.34.0
func WithHandler(handler HandlerFunc) OperationOption
WithHandler registers a handler for this operation. The handler is keyed by the operation's method and path. This option only has effect when used with ServerBuilder.AddOperation.
Example:
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(listPetsHandler),
builder.WithResponse(http.StatusOK, []Pet{}),
)
func WithHandlerFunc ¶ added in v1.34.0
func WithHandlerFunc(handler http.HandlerFunc) OperationOption
WithHandlerFunc registers an http.HandlerFunc for this operation. This is a convenience option for handlers that don't need typed request/response handling. The handler is keyed by the operation's method and path. This option only has effect when used with ServerBuilder.AddOperation.
Example:
srv.AddOperation(http.MethodGet, "/health",
builder.WithHandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}),
)
func WithHeaderParam ¶
func WithHeaderParam(name string, paramType any, opts ...ParamOption) OperationOption
WithHeaderParam adds a header parameter to the operation.
func WithNoSecurity ¶
func WithNoSecurity() OperationOption
WithNoSecurity explicitly marks the operation as requiring no security.
func WithOperationExtension ¶ added in v1.30.0
func WithOperationExtension(key string, value any) OperationOption
WithOperationExtension adds a vendor extension (x-* field) to the operation. The key must start with "x-" as per the OpenAPI specification. Extensions are preserved in both OAS 2.0 and OAS 3.x output.
Example:
builder.AddOperation("GET", "/users",
builder.WithOperationExtension("x-rate-limit", 100),
builder.WithOperationExtension("x-internal", true),
)
func WithOperationID ¶
func WithOperationID(id string) OperationOption
WithOperationID sets the operation ID.
func WithParameter ¶
func WithParameter(param *parser.Parameter) OperationOption
WithParameter adds a pre-built parameter to the operation.
func WithParameterRef ¶
func WithParameterRef(ref string) OperationOption
WithParameterRef adds a parameter reference to the operation.
func WithPathParam ¶
func WithPathParam(name string, paramType any, opts ...ParamOption) OperationOption
WithPathParam adds a path parameter to the operation. Note: Path parameters are always required per the OAS spec.
func WithProduces ¶ added in v1.30.0
func WithProduces(mimeTypes ...string) OperationOption
WithProduces sets the produces MIME types for the operation. This is only applicable to OAS 2.0 specifications. For OAS 3.x, use WithResponseContentTypes instead to specify multiple content types.
Example:
builder.AddOperation("GET", "/users/{id}",
builder.WithProduces("application/json", "application/xml"),
builder.WithResponse(200, User{}),
)
func WithQueryParam ¶
func WithQueryParam(name string, paramType any, opts ...ParamOption) OperationOption
WithQueryParam adds a query parameter to the operation.
func WithRequestBody ¶
func WithRequestBody(contentType string, bodyType any, opts ...RequestBodyOption) OperationOption
WithRequestBody sets the request body for the operation. The bodyType is reflected to generate the schema.
func WithRequestBodyContentTypes ¶ added in v1.30.0
func WithRequestBodyContentTypes(contentTypes []string, bodyType any, opts ...RequestBodyOption) OperationOption
WithRequestBodyContentTypes sets the request body for the operation with multiple content types. All content types share the same schema. This is primarily useful for OAS 3.x specifications where the request body content map can contain multiple media types.
For OAS 2.0, only the first content type is used for the body parameter schema, and you should set the consumes array separately using WithConsumes.
Example:
builder.AddOperation("POST", "/users",
builder.WithRequestBodyContentTypes(
[]string{"application/json", "application/xml"},
User{},
builder.WithRequired(true),
),
)
func WithRequestBodyRawSchema ¶ added in v1.15.0
func WithRequestBodyRawSchema(contentType string, schema *parser.Schema, opts ...RequestBodyOption) OperationOption
WithRequestBodyRawSchema sets the request body for the operation with a pre-built schema. This is useful when you need full control over the schema structure or when working with schemas that cannot be easily represented with Go types (e.g., file uploads, oneOf/anyOf).
Example:
schema := &parser.Schema{
Type: "string",
Format: "binary",
}
WithRequestBodyRawSchema("application/octet-stream", schema)
func WithResponse ¶
func WithResponse(statusCode int, responseType any, opts ...ResponseOption) OperationOption
WithResponse adds a response to the operation. The responseType is reflected to generate the schema. Use WithResponseContentType to specify a content type other than "application/json".
func WithResponseContentTypes ¶ added in v1.30.0
func WithResponseContentTypes(statusCode int, contentTypes []string, responseType any, opts ...ResponseOption) OperationOption
WithResponseContentTypes adds a response with multiple content types to the operation. All content types share the same schema. This is primarily useful for OAS 3.x specifications where the response content map can contain multiple media types.
For OAS 2.0, only the first content type is used for the response schema, and you should set the produces array separately using WithProduces.
Example:
builder.AddOperation("GET", "/users/{id}",
builder.WithResponseContentTypes(
200,
[]string{"application/json", "application/xml"},
User{},
builder.WithResponseDescription("User found"),
),
)
func WithResponseRawSchema ¶ added in v1.15.0
func WithResponseRawSchema(statusCode int, contentType string, schema *parser.Schema, opts ...ResponseOption) OperationOption
WithResponseRawSchema adds a response to the operation with a pre-built schema. This is useful when you need full control over the schema structure or when working with schemas that cannot be easily represented with Go types (e.g., file downloads, oneOf/anyOf).
Example:
schema := &parser.Schema{
Type: "string",
Format: "binary",
}
WithResponseRawSchema(200, "application/octet-stream", schema,
WithResponseDescription("File download"))
func WithResponseRef ¶
func WithResponseRef(statusCode int, ref string) OperationOption
WithResponseRef adds a response reference to the operation.
func WithSecurity ¶
func WithSecurity(requirements ...parser.SecurityRequirement) OperationOption
WithSecurity sets the security requirements for the operation.
func WithSummary ¶
func WithSummary(summary string) OperationOption
WithSummary sets the operation summary.
type ParamOption ¶
type ParamOption func(*paramConfig)
ParamOption configures a parameter.
func WithParamAllowEmptyValue ¶ added in v1.30.0
func WithParamAllowEmptyValue(allow bool) ParamOption
WithParamAllowEmptyValue sets whether the parameter allows empty values. This is only applicable to OAS 2.0 specifications for query and formData parameters. Setting this to true allows sending a parameter with an empty value.
Example:
builder.WithQueryParam("filter", "",
builder.WithParamAllowEmptyValue(true),
)
func WithParamCollectionFormat ¶ added in v1.30.0
func WithParamCollectionFormat(format string) ParamOption
WithParamCollectionFormat sets the collection format for array parameters. This is only applicable to OAS 2.0 specifications.
Valid values are:
- "csv": comma separated values (default) - foo,bar
- "ssv": space separated values - foo bar
- "tsv": tab separated values - foo\tbar
- "pipes": pipe separated values - foo|bar
- "multi": corresponds to multiple parameter instances - foo=bar&foo=baz
Example:
builder.WithQueryParam("tags", []string{},
builder.WithParamCollectionFormat("csv"),
)
func WithParamDefault ¶ added in v1.13.1
func WithParamDefault(value any) ParamOption
WithParamDefault sets the default value for the parameter.
func WithParamDeprecated ¶
func WithParamDeprecated(deprecated bool) ParamOption
WithParamDeprecated marks the parameter as deprecated.
func WithParamDescription ¶
func WithParamDescription(desc string) ParamOption
WithParamDescription sets the parameter description.
func WithParamEnum ¶ added in v1.13.1
func WithParamEnum(values ...any) ParamOption
WithParamEnum sets the allowed values for the parameter.
func WithParamExample ¶
func WithParamExample(example any) ParamOption
WithParamExample sets the parameter example.
func WithParamExclusiveMaximum ¶ added in v1.13.1
func WithParamExclusiveMaximum(exclusive bool) ParamOption
WithParamExclusiveMaximum sets whether the maximum is exclusive.
func WithParamExclusiveMinimum ¶ added in v1.13.1
func WithParamExclusiveMinimum(exclusive bool) ParamOption
WithParamExclusiveMinimum sets whether the minimum is exclusive.
func WithParamExtension ¶ added in v1.30.0
func WithParamExtension(key string, value any) ParamOption
WithParamExtension adds a vendor extension (x-* field) to the parameter. The key must start with "x-" as per the OpenAPI specification. Extensions are preserved in both OAS 2.0 and OAS 3.x output.
Example:
builder.WithQueryParam("limit", 0,
builder.WithParamExtension("x-example-values", []int{10, 25, 50}),
)
func WithParamFormat ¶ added in v1.33.0
func WithParamFormat(format string) ParamOption
WithParamFormat sets an explicit OpenAPI format for the parameter. This overrides the format that would be inferred from the Go type.
Common formats include: "int32", "int64", "float", "double", "byte", "binary", "date", "date-time", "password", "email", "uri", "uuid", "hostname", "ipv4", "ipv6".
Example:
builder.WithQueryParam("user_id", "",
builder.WithParamFormat("uuid"),
)
func WithParamMaxItems ¶ added in v1.13.1
func WithParamMaxItems(max int) ParamOption
WithParamMaxItems sets the maximum number of items for array parameters.
func WithParamMaxLength ¶ added in v1.13.1
func WithParamMaxLength(max int) ParamOption
WithParamMaxLength sets the maximum length for string parameters.
func WithParamMaximum ¶ added in v1.13.1
func WithParamMaximum(max float64) ParamOption
WithParamMaximum sets the maximum value for numeric parameters.
func WithParamMinItems ¶ added in v1.13.1
func WithParamMinItems(min int) ParamOption
WithParamMinItems sets the minimum number of items for array parameters.
func WithParamMinLength ¶ added in v1.13.1
func WithParamMinLength(min int) ParamOption
WithParamMinLength sets the minimum length for string parameters.
func WithParamMinimum ¶ added in v1.13.1
func WithParamMinimum(min float64) ParamOption
WithParamMinimum sets the minimum value for numeric parameters.
func WithParamMultipleOf ¶ added in v1.13.1
func WithParamMultipleOf(value float64) ParamOption
WithParamMultipleOf sets the multipleOf constraint for numeric parameters.
func WithParamPattern ¶ added in v1.13.1
func WithParamPattern(pattern string) ParamOption
WithParamPattern sets the pattern (regex) for string parameters.
func WithParamRequired ¶
func WithParamRequired(required bool) ParamOption
WithParamRequired sets whether the parameter is required.
func WithParamSchema ¶ added in v1.33.0
func WithParamSchema(schema *parser.Schema) ParamOption
WithParamSchema sets a complete schema for the parameter. This takes precedence over type/format inference and the WithParamType/WithParamFormat options.
Use this for complex schemas that cannot be easily represented with Go types (e.g., oneOf, arrays with specific item constraints).
Example:
builder.WithQueryParam("ids", nil,
builder.WithParamSchema(&parser.Schema{
Type: "array",
Items: &parser.Schema{Type: "string", Format: "uuid"},
}),
)
func WithParamType ¶ added in v1.33.0
func WithParamType(typeName string) ParamOption
WithParamType sets an explicit OpenAPI type for the parameter. This overrides the type that would be inferred from the Go type.
Valid types per OpenAPI specification: "string", "integer", "number", "boolean", "array", "object".
Example:
builder.WithQueryParam("data", []byte{},
builder.WithParamType("string"),
builder.WithParamFormat("byte"),
)
func WithParamUniqueItems ¶ added in v1.13.1
func WithParamUniqueItems(unique bool) ParamOption
WithParamUniqueItems sets whether array items must be unique.
type Request ¶ added in v1.34.0
type Request struct {
// HTTPRequest is the original HTTP request.
HTTPRequest *http.Request
// PathParams contains the extracted and validated path parameters.
// Keys are parameter names, values are deserialized values.
PathParams map[string]any
// QueryParams contains the extracted and validated query parameters.
QueryParams map[string]any
// HeaderParams contains the extracted and validated header parameters.
HeaderParams map[string]any
// CookieParams contains the extracted and validated cookie parameters.
CookieParams map[string]any
// Body is the unmarshaled request body (typically a map or struct).
Body any
// RawBody is the raw request body bytes.
RawBody []byte
// OperationID is the operation ID for this request.
OperationID string
// MatchedPath is the OpenAPI path template that matched (e.g., "/pets/{petId}").
MatchedPath string
}
Request contains validated request data passed to operation handlers.
type RequestBodyOption ¶
type RequestBodyOption func(*requestBodyConfig)
RequestBodyOption configures a request body.
func WithRequestBodyExtension ¶ added in v1.30.0
func WithRequestBodyExtension(key string, value any) RequestBodyOption
WithRequestBodyExtension adds a vendor extension (x-* field) to the request body. The key must start with "x-" as per the OpenAPI specification. Extensions are preserved in OAS 3.x output. For OAS 2.0, request bodies are converted to body parameters, and extensions will be applied to the body parameter.
Example:
builder.AddOperation("POST", "/users",
builder.WithRequestBody("application/json", User{},
builder.WithRequestBodyExtension("x-codegen-request-body-name", "user"),
),
)
func WithRequestDescription ¶
func WithRequestDescription(desc string) RequestBodyOption
WithRequestDescription sets the request body description.
func WithRequestExample ¶
func WithRequestExample(example any) RequestBodyOption
WithRequestExample sets the request body example.
func WithRequired ¶
func WithRequired(required bool) RequestBodyOption
WithRequired sets whether the request body is required.
type Response ¶ added in v1.34.0
type Response interface {
// StatusCode returns the HTTP status code.
StatusCode() int
// Headers returns the HTTP headers to include in the response.
Headers() http.Header
// Body returns the response body (may be nil for no-content responses).
Body() any
// WriteTo writes the response to the ResponseWriter.
WriteTo(w http.ResponseWriter) error
}
Response is implemented by response types. All response helpers return types that implement this interface.
func Error ¶ added in v1.34.0
Error creates an error response with status and message.
Example:
return builder.Error(http.StatusNotFound, "pet not found")
func ErrorWithDetails ¶ added in v1.34.0
ErrorWithDetails creates an error response with additional details.
Example:
return builder.ErrorWithDetails(http.StatusBadRequest, "validation failed", errors)
func JSON ¶ added in v1.34.0
JSON creates a JSON response with the given status and body.
Example:
return builder.JSON(http.StatusOK, pets)
func NoContent ¶ added in v1.34.0
func NoContent() Response
NoContent creates a 204 No Content response.
Example:
return builder.NoContent()
type ResponseBuilder ¶ added in v1.34.0
type ResponseBuilder struct {
// contains filtered or unexported fields
}
ResponseBuilder provides fluent response construction.
func NewResponse ¶ added in v1.34.0
func NewResponse(status int) *ResponseBuilder
NewResponse creates a new ResponseBuilder.
Example:
return builder.NewResponse(http.StatusOK).
Header("X-Request-Id", requestID).
JSON(pets)
func (*ResponseBuilder) Binary ¶ added in v1.34.0
func (b *ResponseBuilder) Binary(contentType string, data []byte) Response
Binary sets a binary body.
func (*ResponseBuilder) Body ¶ added in v1.34.0
func (b *ResponseBuilder) Body() any
func (*ResponseBuilder) Header ¶ added in v1.34.0
func (b *ResponseBuilder) Header(key, value string) *ResponseBuilder
Header adds a header to the response.
func (*ResponseBuilder) Headers ¶ added in v1.34.0
func (b *ResponseBuilder) Headers() http.Header
func (*ResponseBuilder) JSON ¶ added in v1.34.0
func (b *ResponseBuilder) JSON(body any) Response
JSON sets a JSON body.
func (*ResponseBuilder) StatusCode ¶ added in v1.34.0
func (b *ResponseBuilder) StatusCode() int
func (*ResponseBuilder) Text ¶ added in v1.34.0
func (b *ResponseBuilder) Text(body string) Response
Text sets a plain text body.
func (*ResponseBuilder) WriteTo ¶ added in v1.34.0
func (b *ResponseBuilder) WriteTo(w http.ResponseWriter) error
func (*ResponseBuilder) XML ¶ added in v1.34.0
func (b *ResponseBuilder) XML(body any) Response
XML sets an XML body.
type ResponseOption ¶
type ResponseOption func(*responseConfig)
ResponseOption configures a response.
func WithResponseContentType ¶
func WithResponseContentType(contentType string) ResponseOption
WithResponseContentType sets the content type for the response. Defaults to "application/json" if not specified.
func WithResponseDescription ¶
func WithResponseDescription(desc string) ResponseOption
WithResponseDescription sets the response description.
func WithResponseExample ¶
func WithResponseExample(example any) ResponseOption
WithResponseExample sets the response example.
func WithResponseExtension ¶ added in v1.30.0
func WithResponseExtension(key string, value any) ResponseOption
WithResponseExtension adds a vendor extension (x-* field) to the response. The key must start with "x-" as per the OpenAPI specification. Extensions are preserved in both OAS 2.0 and OAS 3.x output.
Example:
builder.WithResponse(200, User{},
builder.WithResponseExtension("x-cache-ttl", 3600),
)
func WithResponseHeader ¶
func WithResponseHeader(name string, header *parser.Header) ResponseOption
WithResponseHeader adds a header to the response.
type RouterStrategy ¶ added in v1.34.0
type RouterStrategy interface {
// Build creates an http.Handler that routes requests to the dispatcher.
// Returns an error if the routes cannot be configured (e.g., invalid path patterns).
Build(routes []operationRoute, dispatcher http.Handler) (http.Handler, error)
// PathParam extracts a path parameter from the request context.
PathParam(r *http.Request, name string) string
}
RouterStrategy defines how paths are matched to handlers. The stdlib router implements this interface. Additional router implementations (e.g., chi, gorilla/mux) can implement this interface for custom routing.
type SchemaFieldProcessor ¶ added in v1.36.0
SchemaFieldProcessor is called for each struct field during schema generation. It receives the generated schema and the struct field, and returns a potentially modified schema. The processor is called after oastools applies any oas:"..." tags.
This hook enables libraries to support custom tag formats alongside the standard oas:"..." tags. For example, a library could support legacy standalone tags:
type User struct {
Name string `json:"name" description:"User's full name"`
}
The processor can read these tags and apply them to the schema:
func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
return schema
}
func ComposeSchemaFieldProcessors ¶ added in v1.36.0
func ComposeSchemaFieldProcessors(processors ...SchemaFieldProcessor) SchemaFieldProcessor
ComposeSchemaFieldProcessors chains multiple processors into a single processor. Processors are executed in order, with each receiving the schema returned by the previous. This enables composing multiple independent tag processors into a single pipeline.
If no processors are provided, returns nil. If only one processor is provided, returns that processor directly. Nil processors in the list are skipped.
Example - combining legacy tag support with custom validation:
descriptionProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if desc := field.Tag.Get("description"); desc != "" {
schema.Description = desc
}
return schema
}
enumProcessor := func(schema *parser.Schema, field reflect.StructField) *parser.Schema {
if enumStr := field.Tag.Get("enum"); enumStr != "" {
values := strings.Split(enumStr, "|")
schema.Enum = make([]any, len(values))
for i, v := range values {
schema.Enum[i] = strings.TrimSpace(v)
}
}
return schema
}
// Combine both processors
spec := builder.New(parser.OASVersion320,
builder.WithSchemaFieldProcessor(
builder.ComposeSchemaFieldProcessors(descriptionProcessor, enumProcessor),
),
)
type SchemaNameContext ¶ added in v1.25.0
type SchemaNameContext struct {
// Type is the Go type name without package (e.g., "User", "Response[T]").
Type string
// TypeSanitized is Type with generic brackets replaced per GenericNamingStrategy.
TypeSanitized string
// TypeBase is the base type name without generic parameters (e.g., "Response").
TypeBase string
// Package is the package base name (e.g., "models").
Package string
// PackagePath is the full import path (e.g., "github.com/org/models").
PackagePath string
// PackagePathSanitized is PackagePath with slashes replaced
// (e.g., "github.com_org_models").
PackagePathSanitized string
// IsGeneric indicates if the type has type parameters.
IsGeneric bool
// GenericParams contains the type parameter names if IsGeneric is true.
GenericParams []string
// GenericParamsSanitized contains sanitized type parameter names.
GenericParamsSanitized []string
// GenericSuffix is the formatted generic parameters portion.
// Varies based on GenericNamingStrategy (e.g., "_User_", "OfUser", "<User>").
GenericSuffix string
// IsAnonymous indicates if this is an anonymous struct type.
IsAnonymous bool
// IsPointer indicates if the original type was a pointer.
IsPointer bool
// Kind is the reflect.Kind as a string (e.g., "struct", "slice", "map").
Kind string
}
SchemaNameContext provides type metadata for custom naming templates and functions. All fields are populated before being passed to templates or custom naming functions.
type SchemaNameFunc ¶ added in v1.25.0
type SchemaNameFunc func(ctx SchemaNameContext) string
SchemaNameFunc is the signature for custom schema naming functions. The function receives a SchemaNameContext with complete type metadata and should return the desired schema name.
type SchemaNamingStrategy ¶ added in v1.25.0
type SchemaNamingStrategy int
SchemaNamingStrategy defines built-in schema naming conventions. Use these with WithSchemaNaming to control how schema names are generated from Go types.
const ( // SchemaNamingDefault uses "package.TypeName" format (current behavior). // Example: models.User SchemaNamingDefault SchemaNamingStrategy = iota // SchemaNamingPascalCase uses "PackageTypeName" format. // Example: models.User -> ModelsUser SchemaNamingPascalCase // SchemaNamingCamelCase uses "packageTypeName" format. // Example: models.User -> modelsUser SchemaNamingCamelCase // SchemaNamingSnakeCase uses "package_type_name" format. // Example: models.User -> models_user SchemaNamingSnakeCase // SchemaNamingKebabCase uses "package-type-name" format. // Example: models.User -> models-user SchemaNamingKebabCase // SchemaNamingTypeOnly uses just "TypeName" without package. // Example: models.User -> User // Warning: May cause conflicts with same-named types in different packages. SchemaNamingTypeOnly // SchemaNamingFullPath uses full package path. // Example: models.User -> github.com_org_models_User SchemaNamingFullPath )
type ServerBuilder ¶ added in v1.34.0
type ServerBuilder struct {
*Builder
// contains filtered or unexported fields
}
ServerBuilder extends Builder to support server construction. It embeds Builder, inheriting all specification construction methods.
Concurrency: ServerBuilder instances are not safe for concurrent use. Create separate ServerBuilder instances for concurrent operations.
func FromBuilder ¶ added in v1.34.0
func FromBuilder(b *Builder, opts ...ServerBuilderOption) *ServerBuilder
FromBuilder creates a ServerBuilder from an existing Builder. This allows converting an existing specification into a runnable server.
Example:
b := builder.New(parser.OASVersion320).SetTitle("My API")
srv := builder.FromBuilder(b)
srv.Handle(http.MethodGet, "/users", listUsersHandler)
func NewServerBuilder ¶ added in v1.34.0
func NewServerBuilder(version parser.OASVersion, opts ...ServerBuilderOption) *ServerBuilder
NewServerBuilder creates a ServerBuilder for the specified OAS version. This is the primary entry point for the server builder API.
Example:
srv := builder.NewServerBuilder(parser.OASVersion320).
SetTitle("Pet Store API").
SetVersion("1.0.0")
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(listPetsHandler),
builder.WithResponse(http.StatusOK, []Pet{}),
)
result, err := srv.BuildServer()
func (*ServerBuilder) AddOperation ¶ added in v1.34.0
func (s *ServerBuilder) AddOperation(method, path string, opts ...OperationOption) *ServerBuilder
AddOperation adds an operation and returns the ServerBuilder for chaining. Overrides Builder.AddOperation to support inline handler registration via WithHandler.
Example:
srv.AddOperation(http.MethodGet, "/pets",
builder.WithHandler(listPetsHandler),
builder.WithResponse(http.StatusOK, []Pet{}),
)
func (*ServerBuilder) AddSecurityScheme ¶ added in v1.34.0
func (s *ServerBuilder) AddSecurityScheme(name string, scheme *parser.SecurityScheme) *ServerBuilder
AddSecurityScheme adds a security scheme. Overrides Builder.AddSecurityScheme to maintain fluent chaining.
func (*ServerBuilder) AddServer ¶ added in v1.34.0
func (s *ServerBuilder) AddServer(url string, opts ...ServerOption) *ServerBuilder
AddServer adds a server definition. Overrides Builder.AddServer to maintain fluent chaining.
func (*ServerBuilder) AddTag ¶ added in v1.34.0
func (s *ServerBuilder) AddTag(name string, opts ...TagOption) *ServerBuilder
AddTag adds a tag definition. Overrides Builder.AddTag to maintain fluent chaining.
func (*ServerBuilder) BuildServer ¶ added in v1.34.0
func (s *ServerBuilder) BuildServer() (*ServerResult, error)
BuildServer constructs the http.Handler and related artifacts. Returns an error if the OAS document is invalid or the router cannot be configured.
Operations without registered handlers will return 501 Not Implemented at runtime. To enforce that all operations have handlers, check the handlers map before calling BuildServer.
Example:
result, err := srv.BuildServer()
if err != nil {
log.Fatal(err)
}
http.ListenAndServe(":8080", result.Handler)
func (*ServerBuilder) Handle ¶ added in v1.34.0
func (s *ServerBuilder) Handle(method, path string, handler HandlerFunc) *ServerBuilder
Handle registers a handler for an operation by method and path. This is an alternative to using WithHandler in AddOperation, useful for dynamic handler registration or when the handler isn't known at definition time.
Example:
srv.Handle(http.MethodGet, "/pets", func(ctx context.Context, req *builder.Request) builder.Response {
return builder.JSON(http.StatusOK, pets)
})
func (*ServerBuilder) HandleFunc ¶ added in v1.34.0
func (s *ServerBuilder) HandleFunc(method, path string, handler http.HandlerFunc) *ServerBuilder
HandleFunc registers a handler using a standard http.HandlerFunc signature. This is useful for operations that don't need typed parameters.
Example:
srv.HandleFunc(http.MethodGet, "/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
func (*ServerBuilder) MustBuildServer ¶ added in v1.34.0
func (s *ServerBuilder) MustBuildServer() *ServerResult
MustBuildServer is like BuildServer but panics on error. Useful for main() or init() where errors are fatal.
func (*ServerBuilder) SetDescription ¶ added in v1.34.0
func (s *ServerBuilder) SetDescription(desc string) *ServerBuilder
SetDescription sets the API description. Overrides Builder.SetDescription to maintain fluent chaining.
func (*ServerBuilder) SetSecurity ¶ added in v1.34.0
func (s *ServerBuilder) SetSecurity(requirements ...parser.SecurityRequirement) *ServerBuilder
SetSecurity sets global security requirements. Overrides Builder.SetSecurity to maintain fluent chaining.
func (*ServerBuilder) SetTitle ¶ added in v1.34.0
func (s *ServerBuilder) SetTitle(title string) *ServerBuilder
SetTitle sets the API title. Overrides Builder.SetTitle to maintain fluent chaining.
func (*ServerBuilder) SetVersion ¶ added in v1.34.0
func (s *ServerBuilder) SetVersion(version string) *ServerBuilder
SetVersion sets the API version. Overrides Builder.SetVersion to maintain fluent chaining.
func (*ServerBuilder) Use ¶ added in v1.34.0
func (s *ServerBuilder) Use(mw ...Middleware) *ServerBuilder
Use adds middleware to the server. Middleware is applied in order: first added = outermost (executes first on request). For example, Use(A, B) results in: A(B(handler)), so A runs first.
Example:
srv.Use(loggingMiddleware, corsMiddleware)
type ServerBuilderOption ¶ added in v1.34.0
type ServerBuilderOption func(*serverBuilderConfig)
ServerBuilderOption configures a ServerBuilder.
func WithErrorHandler ¶ added in v1.34.0
func WithErrorHandler(handler ErrorHandler) ServerBuilderOption
WithErrorHandler sets the error handler for handler panics and errors.
func WithMethodNotAllowedHandler ¶ added in v1.34.0
func WithMethodNotAllowedHandler(handler http.Handler) ServerBuilderOption
WithMethodNotAllowedHandler sets the handler for unmatched methods.
func WithNotFoundHandler ¶ added in v1.34.0
func WithNotFoundHandler(handler http.Handler) ServerBuilderOption
WithNotFoundHandler sets the handler for unmatched paths.
func WithRecovery ¶ added in v1.34.0
func WithRecovery() ServerBuilderOption
WithRecovery enables panic recovery middleware. Recovered panics are passed to the error handler.
func WithRequestLogging ¶ added in v1.34.0
func WithRequestLogging(logger func(method, path string, status int, duration time.Duration)) ServerBuilderOption
WithRequestLogging enables request logging middleware.
func WithRouter ¶ added in v1.34.0
func WithRouter(strategy RouterStrategy) ServerBuilderOption
WithRouter sets the routing strategy. Default: StdlibRouter (uses net/http with PathMatcherSet).
func WithStdlibRouter ¶ added in v1.34.0
func WithStdlibRouter() ServerBuilderOption
WithStdlibRouter uses net/http with PathMatcherSet for routing. This is the default and adds no dependencies.
func WithValidationConfig ¶ added in v1.34.0
func WithValidationConfig(validationCfg ValidationConfig) ServerBuilderOption
WithValidationConfig sets validation middleware configuration.
func WithoutValidation ¶ added in v1.34.0
func WithoutValidation() ServerBuilderOption
WithoutValidation disables automatic request validation. Use when validation is handled elsewhere or for maximum performance.
type ServerOption ¶
type ServerOption func(*serverConfig)
ServerOption configures a server.
func WithServerDescription ¶
func WithServerDescription(desc string) ServerOption
WithServerDescription sets the server description.
func WithServerVariable ¶
func WithServerVariable(name, defaultValue string, opts ...ServerVariableOption) ServerOption
WithServerVariable adds a variable to the server.
type ServerResult ¶ added in v1.34.0
type ServerResult struct {
// Handler is the HTTP handler ready to serve requests.
Handler http.Handler
// Spec is the built OAS document (*parser.OAS3Document or *parser.OAS2Document).
Spec any
// ParseResult is the parse result for compatibility with other packages.
ParseResult *parser.ParseResult
// Validator is the httpvalidator instance (nil if validation is disabled).
Validator *httpvalidator.Validator
}
ServerResult contains the built server and related artifacts.
type ServerTest ¶ added in v1.34.0
type ServerTest struct {
Result *ServerResult
}
ServerTest provides testing utilities for a built server.
func NewServerTest ¶ added in v1.34.0
func NewServerTest(result *ServerResult) *ServerTest
NewServerTest creates a ServerTest from a ServerResult. Panics if result is nil or result.Handler is nil, indicating a test setup error.
Example:
result := srv.MustBuildServer() test := builder.NewServerTest(result) rec := test.Execute(builder.NewTestRequest(http.MethodGet, "/pets"))
func (*ServerTest) Delete ¶ added in v1.34.0
func (t *ServerTest) Delete(path string) *httptest.ResponseRecorder
Delete performs a DELETE request.
Example:
rec := test.Delete("/pets/123")
func (*ServerTest) Execute ¶ added in v1.34.0
func (t *ServerTest) Execute(req *TestRequest) *httptest.ResponseRecorder
Execute runs a request and returns the recorder.
func (*ServerTest) GetJSON ¶ added in v1.34.0
func (t *ServerTest) GetJSON(path string, target any) (*httptest.ResponseRecorder, error)
GetJSON performs a GET and unmarshals the JSON response.
Example:
var pets []Pet
rec, err := test.GetJSON("/pets", &pets)
func (*ServerTest) PostJSON ¶ added in v1.34.0
func (t *ServerTest) PostJSON(path string, body any, target any) (*httptest.ResponseRecorder, error)
PostJSON performs a POST with a JSON body and unmarshals the response.
Example:
var created Pet
rec, err := test.PostJSON("/pets", newPet, &created)
func (*ServerTest) PutJSON ¶ added in v1.34.0
func (t *ServerTest) PutJSON(path string, body any, target any) (*httptest.ResponseRecorder, error)
PutJSON performs a PUT with a JSON body and unmarshals the response.
Example:
var updated Pet
rec, err := test.PutJSON("/pets/123", updatedPet, &updated)
func (*ServerTest) Request ¶ added in v1.34.0
func (t *ServerTest) Request(method, path string) *TestRequest
Request creates a test request builder.
type ServerVariableOption ¶
type ServerVariableOption func(*serverVariableConfig)
ServerVariableOption configures a server variable.
func WithServerVariableDescription ¶
func WithServerVariableDescription(desc string) ServerVariableOption
WithServerVariableDescription sets the description for a server variable.
func WithServerVariableEnum ¶
func WithServerVariableEnum(values ...string) ServerVariableOption
WithServerVariableEnum sets the enum values for a server variable.
type TagOption ¶
type TagOption func(*tagConfig)
TagOption configures a tag.
func WithTagDescription ¶
WithTagDescription sets the tag description.
func WithTagExternalDocs ¶
WithTagExternalDocs sets the external documentation for a tag.
type TestRequest ¶ added in v1.34.0
type TestRequest struct {
// contains filtered or unexported fields
}
TestRequest builds requests for testing.
func NewTestRequest ¶ added in v1.34.0
func NewTestRequest(method, path string) *TestRequest
NewTestRequest creates a new test request builder.
Example:
req := builder.NewTestRequest(http.MethodGet, "/pets").
Query("limit", "10").
Header("Authorization", "Bearer token")
func (*TestRequest) Body ¶ added in v1.34.0
func (r *TestRequest) Body(contentType string, body io.Reader) *TestRequest
Body sets a raw request body.
func (*TestRequest) Build ¶ added in v1.34.0
func (r *TestRequest) Build() *http.Request
Build creates the http.Request.
func (*TestRequest) Execute ¶ added in v1.34.0
func (r *TestRequest) Execute(handler http.Handler) *httptest.ResponseRecorder
Execute runs the request against a handler and returns the response.
func (*TestRequest) Header ¶ added in v1.34.0
func (r *TestRequest) Header(key, value string) *TestRequest
Header adds a header.
func (*TestRequest) JSONBody ¶ added in v1.34.0
func (r *TestRequest) JSONBody(body any) *TestRequest
JSONBody sets a JSON request body. Panics if the body cannot be marshaled to JSON, indicating a test setup error.
func (*TestRequest) Query ¶ added in v1.34.0
func (r *TestRequest) Query(key, value string) *TestRequest
Query adds a query parameter.
type ValidationConfig ¶ added in v1.34.0
type ValidationConfig struct {
// IncludeRequestValidation enables request validation (default: true).
IncludeRequestValidation bool
// IncludeResponseValidation enables response validation (default: false).
IncludeResponseValidation bool
// StrictMode treats warnings as errors (default: false).
StrictMode bool
// OnValidationError is called when validation fails.
// If nil, a default JSON error response is returned.
OnValidationError ValidationErrorHandler
}
ValidationConfig configures request/response validation.
func DefaultValidationConfig ¶ added in v1.34.0
func DefaultValidationConfig() ValidationConfig
DefaultValidationConfig returns sensible defaults for validation.
type ValidationErrorHandler ¶ added in v1.34.0
type ValidationErrorHandler func(w http.ResponseWriter, r *http.Request, result *httpvalidator.RequestValidationResult)
ValidationErrorHandler handles validation failures.
Source Files
¶
- builder.go
- constraints.go
- doc.go
- errors.go
- naming.go
- operation.go
- options.go
- parameter.go
- reflect.go
- reflect_cache.go
- response.go
- security.go
- server.go
- server_builder.go
- server_builder_options.go
- server_dispatcher.go
- server_response.go
- server_router_stdlib.go
- server_testing.go
- server_types.go
- server_validation.go
- tags.go