A powerful OpenAPI 3.x Go code generator that weaves your API specifications into production-ready server code.
SpecWeaver automatically generates type-safe Go code from OpenAPI specifications, including data types, HTTP handlers, and routing logic. Uses a custom robust OpenAPI parser supporting versions 3.0.x, 3.1.x, and 3.2.x with no external OpenAPI dependencies.
- ✨ Full OpenAPI 3.x Support - Compatible with OpenAPI 3.0.x, 3.1.x, and 3.2.x
- 🔧 Custom Robust Parser - No external OpenAPI library dependencies
- 🎯 Type-Safe Code - Generates idiomatic Go structs with proper types
- 🔐 Authentication Support - Automatic generation of auth middleware for all OpenAPI security schemes (Basic, Bearer, API Key, OAuth2, OIDC)
- 🪝 Webhooks Support - Generate type-safe webhook clients from OpenAPI 3.1+ webhook definitions
- 🚀 Production Ready - Includes error handling, middleware, and best practices
- 📝 Documentation Preserved - OpenAPI descriptions become Go comments
- 🔄 Schema References - Properly resolves
$refto generate correct types - 🎨 Idiomatic Go - Follows Go conventions and best practices (uses
anyinstead ofinterface{}) - ⚡ Zero Dependencies - Custom lightweight router, no external dependencies
- 🔌 Custom Router Support - Use any router (chi, gorilla/mux, etc.) via pluggable interface
- 📄 Format Support - Works with both YAML and JSON specifications
# Clone the repository
git clone https://github.com/christopherklint97/specweaver.git
cd specweaver
# Build the tool
go build -o specweaver ./cmd/specweaver
# Optionally, install globally
go install ./cmd/specweaver# Add to your project
go get github.com/christopherklint97/specweaver@latestThen import in your Go code:
import "github.com/christopherklint97/specweaver"./specweaver -spec examples/petstore.yaml -output ./generatedOptions:
-spec- Path to your OpenAPI specification file (YAML or JSON) - required-output- Output directory for generated code (default:./generated)-package- Package name for generated code (default:api)-version- Show version information
The generator creates a Server interface with clean, testable methods using context.Context:
package main
import (
"context"
"net/http"
"github.com/yourorg/yourapp/generated/api"
)
type MyServer struct {
// Your application state
}
// Implement the interface methods with context-based handlers
func (s *MyServer) ListPets(ctx context.Context, req api.ListPetsRequest) (api.ListPetsResponse, error) {
// Access query parameters
limit := 20
if req.Limit != nil {
limit = int(*req.Limit)
}
pets := []api.Pet{
{Id: 1, Name: "Fluffy", Status: api.PetStatusAvailable},
}
// Return typed response
return api.ListPets200Response{Body: pets}, nil
}
func (s *MyServer) CreatePet(ctx context.Context, req api.CreatePetRequest) (api.CreatePetResponse, error) {
// Validation with custom status code
if req.Body.Name == "" {
return nil, api.NewHTTPError(http.StatusBadRequest, "name is required")
}
// Process the new pet...
pet := api.Pet{
Id: 1,
Name: req.Body.Name,
}
// Return 201 Created response
return api.CreatePet201Response{Body: pet}, nil
}
func (s *MyServer) GetPetById(ctx context.Context, req api.GetPetByIdRequest) (api.GetPetByIdResponse, error) {
// Access path parameters
petId := req.PetId
pet, exists := s.findPet(petId)
if !exists {
// Return 404 response (not an error!)
return api.GetPetById404Response{
Body: api.Error{
Error: "Not Found",
Message: "pet not found",
},
}, nil
}
return api.GetPetById200Response{Body: pet}, nil
}
// Helper method
func (s *MyServer) findPet(id int64) (api.Pet, bool) {
// Your pet lookup logic
return api.Pet{}, false
}func main() {
server := &MyServer{}
router := api.NewRouter(server)
log.Println("Starting server on :8080")
http.ListenAndServe(":8080", router)
}You can also use SpecWeaver as a Go module library to programmatically generate code in your applications, build tools, or CI/CD pipelines.
package main
import (
"log"
"github.com/christopherklint97/specweaver"
)
func main() {
// Generate code with a single function call
err := specweaver.Generate("openapi.yaml", specweaver.Options{
OutputDir: "./generated",
PackageName: "api",
})
if err != nil {
log.Fatal(err)
}
}For more control, use the parser and generator separately:
package main
import (
"fmt"
"log"
"github.com/christopherklint97/specweaver"
)
func main() {
// Parse the OpenAPI specification
parser := specweaver.NewParser()
err := parser.ParseFile("openapi.yaml")
if err != nil {
log.Fatal(err)
}
// Access the parsed spec
spec := parser.GetSpec()
fmt.Printf("Generating code for: %s v%s\n", spec.Info.Title, spec.Info.Version)
// Generate code with custom options
generator := specweaver.NewGenerator(spec, specweaver.Options{
OutputDir: "./api",
PackageName: "myapi",
})
err = generator.Generate()
if err != nil {
log.Fatal(err)
}
}Use Cases:
- Build tool integration (mage, make, custom scripts)
- CI/CD pipeline automation
- Dynamic API generation
- Multi-spec batch processing
See examples/library/ for complete examples and integration patterns.
SpecWeaver supports using any HTTP router that implements the router.Router interface. This allows you to use popular routers like chi, gorilla/mux, or httprouter with SpecWeaver-generated code.
server := &MyServer{}
router := api.NewRouter(server) // Uses built-in router with default middleware
http.ListenAndServe(":8080", router)// Create your custom router
customRouter := NewChiAdapter() // Adapter for chi router
// Add your middleware
customRouter.Use(middleware.Logger)
customRouter.Use(ChiURLParamMiddleware) // Required for URL parameter compatibility
// Configure with SpecWeaver routes
api.ConfigureRouter(customRouter, server)
// Start server
http.ListenAndServe(":8080", customRouter)Requirements for custom routers:
- Implement the
router.Routerinterface - Store URL parameters in context using
router.URLParamKey - Support standard HTTP methods (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
- Support middleware via
Usemethod
See examples/custom-router/ for a complete chi router implementation and adapter example.
SpecWeaver generates the following files:
Contains all your data models:
type Pet struct {
Id int64 `json:"id"`
Name string `json:"name"`
Status PetStatus `json:"status"`
BirthDate *date.Date `json:"birthDate,omitempty"`
CreatedAt *time.Time `json:"createdAt,omitempty"`
Owner *Owner `json:"owner,omitempty"`
}
type PetStatus string
const (
PetStatusAvailable PetStatus = "available"
PetStatusPending PetStatus = "pending"
PetStatusSold PetStatus = "sold"
)Contains clean, context-based server interface, request/response types, and routing:
// Request types for each operation
type ListPetsRequest struct {
Limit *int32 // Query parameter
Tag *string // Query parameter
}
type CreatePetRequest struct {
Body NewPet // Request body
}
type GetPetByIdRequest struct {
PetId int64 // Path parameter
}
// Response interfaces and concrete types
type ListPetsResponse interface {
StatusCode() int
}
type ListPets200Response struct {
Body []Pet
}
func (r ListPets200Response) StatusCode() int { return 200 }
type ListPets500Response struct {
Body Error
}
func (r ListPets500Response) StatusCode() int { return 500 }
// HTTPError for custom error status codes
type HTTPError struct {
Code int
Message string
Err error
}
func NewHTTPError(code int, message string) *HTTPError
func NewHTTPErrorf(code int, format string, args ...any) *HTTPError
func WrapHTTPError(code int, err error, message string) *HTTPError
// Server interface with context-based handlers
type Server interface {
ListPets(ctx context.Context, req ListPetsRequest) (ListPetsResponse, error)
CreatePet(ctx context.Context, req CreatePetRequest) (CreatePetResponse, error)
GetPetById(ctx context.Context, req GetPetByIdRequest) (GetPetByIdResponse, error)
UpdatePet(ctx context.Context, req UpdatePetRequest) (UpdatePetResponse, error)
DeletePet(ctx context.Context, req DeletePetRequest) (DeletePetResponse, error)
}
// Router setup functions
func NewRouter(si Server) *router.Mux
func ConfigureRouter(r router.Router, si Server)
// Helper functions
func WriteJSON(w http.ResponseWriter, code int, data any) error
func WriteResponse(w http.ResponseWriter, resp interface{ StatusCode() int }) error
func WriteError(w http.ResponseWriter, code int, err error) error
func ReadJSON(r *http.Request, v any) errorGenerated when webhooks are defined in the OpenAPI specification:
// Request types for each webhook
type OnNewPetRequest struct {
URL string // Webhook destination URL
Body Pet // Webhook payload
}
type OnPetStatusChangedRequest struct {
URL string
XEventID string // Custom header
XEventTime *string // Optional custom header
Body PetStatusEvent
}
// Response interfaces and types
type OnNewPetResponse interface {
isOnNewPetResponse()
StatusCode() int
ResponseBody() any
}
type OnNewPet200Response struct {
Body WebhookAck
}
// WebhookClient interface
type WebhookClient interface {
OnNewPet(ctx context.Context, req OnNewPetRequest) (OnNewPetResponse, error)
OnPetStatusChanged(ctx context.Context, req OnPetStatusChangedRequest) (OnPetStatusChangedResponse, error)
}
// Default HTTP implementation
type DefaultWebhookClient struct {
HTTPClient *http.Client
}
func NewWebhookClient() *DefaultWebhookClientGenerated when security schemes are defined in the OpenAPI specification. See the authentication example for details.
- Testability: No HTTP dependencies in business logic
- Type Safety: Compile-time checks for all parameters and responses
- Smart Errors: HTTPError provides custom status codes, defaults to 500
- Clean Separation: HTTP adapter layer handles parsing/serialization
- Context Support: Pass deadlines, cancellation, and request-scoped values
A complete working example is available in examples/server/:
# Run the example server
cd examples/server
go run main.go
# Test the API
curl http://localhost:8080/petsThis example demonstrates:
- Complete Server interface implementation with context-based handlers
- Type-safe request structs with path and query parameters
- Response types for different status codes
- HTTPError for custom error status codes
- Clean separation of business logic from HTTP concerns
- Context usage for request-scoped values
See examples/library/ for examples of using SpecWeaver as a Go module library:
# Run the library usage example
cd examples/library
go run main.goThis example demonstrates:
- Simple one-function generation
- Advanced usage with parser and generator
- Accessing the parsed OpenAPI spec
- Integration patterns for build tools and CI/CD
See examples/custom-router/ for a complete example of using a custom router (chi) with SpecWeaver:
# Run the custom router example
cd examples/custom-router
go run main.go
# Test the API
curl http://localhost:8080/petsThis example demonstrates:
- Creating an adapter for the chi router
- Implementing the
router.Routerinterface - URL parameter compatibility middleware
- Using chi-specific middleware with SpecWeaver
- Configuring routes with
ConfigureRouter
See examples/webhooks-server/ for a complete example of using webhooks with SpecWeaver:
# Run the webhooks example
cd examples/webhooks-server
go run main.go
# Subscribe to webhooks
curl -X POST http://localhost:8080/subscriptions \
-H "Content-Type: application/json" \
-d '{
"id": "sub-1",
"url": "https://your-webhook-receiver.com/webhook",
"events": ["newPet", "petStatusChanged"],
"active": true
}'This example demonstrates:
- Defining webhooks in OpenAPI 3.1+ specifications
- Type-safe webhook client generation
- Sending webhooks to subscriber URLs
- Custom headers in webhook requests
- Multiple response status code handling
- Asynchronous webhook delivery
See examples/webhooks-server/README.md for detailed documentation on using webhooks.
SpecWeaver intelligently maps OpenAPI types to Go:
| OpenAPI Type | Format | Go Type |
|---|---|---|
string |
- | string |
string |
date |
date.Date |
string |
date-time |
time.Time |
integer |
int32 |
int |
integer |
int64 |
int64 |
number |
float |
float32 |
number |
double |
float64 |
boolean |
- | bool |
array |
- | []T |
object |
- | struct |
| enum | - | type + constants |
- Use Operation IDs: Define
operationIdin your OpenAPI spec for cleaner handler names - Schema References: Use
$refto reuse schemas and avoid duplication - Descriptions: Add descriptions to schemas and properties - they become Go comments
- Required Fields: Mark fields as required in the spec for proper validation
- Enums: Use enums for fixed sets of values to get type-safe constants
- ✅ Component schemas (objects, arrays, primitives)
- ✅ Schema references (
$ref) - ✅ Enums with const generation
- ✅ Required vs optional fields
- ✅ All HTTP methods (GET, POST, PUT, PATCH, DELETE)
- ✅ Path parameters
- ✅ Query parameters
- ✅ Request/response bodies
- ✅ Nested objects
- ✅ Format specifications (date, date-time, int64, float, etc.)
- ✅ Security schemes (Basic, Bearer, API Key, OAuth2, OIDC)
- ✅ Webhooks (OpenAPI 3.1+)
specweaver/
├── cmd/specweaver/ # CLI tool
├── pkg/
│ ├── openapi/ # Custom OpenAPI parser (3.0-3.2 support)
│ ├── parser/ # Parser coordinator
│ ├── router/ # Custom lightweight HTTP router
│ └── generator/ # Code generators
├── examples/ # Example specs and implementations
└── generated/ # Default output directory
- gopkg.in/yaml.v3 - YAML parsing
- No external OpenAPI library dependencies - Custom implementation for maximum control
- No external routing dependencies - Custom lightweight router
- Minimal dependencies - Generated code uses only:
- Go standard library
github.com/christopherklint97/specweaver/pkg/router- Custom router (no external deps)google.golang.org/genproto/googleapis/type/date- Only whenformat: dateis used
SpecWeaver includes a comprehensive Makefile for development automation. Run make help to see all available targets.
make build # Build the specweaver binary
make install # Install to GOPATH/bin
make clean # Clean build artifacts and generated files
make all # Run clean, fmt, vet, test, and buildmake test # Run all tests
make test-coverage # Run tests with coverage report (generates HTML)
make test-race # Run tests with race detector
make test-verbose # Run tests with verbose output
make test-bench # Run benchmark testsmake fmt # Format all Go code
make vet # Run go vet
make lint # Run golangci-lint (if installed)
make check # Run fmt, vet, and test (pre-commit checks)make generate # Generate code from petstore example
make generate-examples # Regenerate code for all examplesmake example-server # Run the example server
make example-library # Run the library usage example
make example-custom-router # Run the custom router examplemake deps # Download dependencies
make update-deps # Update dependencies to latest versions
make tidy # Run go mod tidymake dev # Quick development cycle (clean, fmt, vet, build)
make watch # Watch for changes and rebuild (requires entr)
make version # Show Go and module versionsmake tree # Show project structure
make size # Show binary size
make todo # Show TODO and FIXME comments in codeSee CLAUDE.md for detailed development documentation, architecture decisions, and contribution guidelines.
This project is licensed under the MIT License - see the LICENSE file for details.
- Uses gopkg.in/yaml.v3 for YAML parsing
- Custom OpenAPI 3.x parser supporting versions 3.0 through 3.2
- Custom lightweight HTTP router with middleware support
- Inspired by the OpenAPI Generator project and the Go community's best practices