A lightweight, framework-agnostic OpenAPI 3.x specification builder for Go that gives you complete control over your API documentation without vendor lock-in.
- 🎯 Framework Agnostic — Works with any Go web framework or as a standalone tool
- ⚡ Zero Dependencies — Powered by
swaggest/openapi-gowith minimal overhead - 🔧 Programmatic Control — Build specs in pure Go code with full type safety
- 🚀 Adapter Ecosystem — Seamless integration with popular frameworks via dedicated adapters
- 📝 CI/CD Ready — Generate specs at build time for documentation pipelines
go get github.com/oaswrap/specFor CI/CD pipelines and build-time spec generation:
package main
import (
"log"
"github.com/oaswrap/spec"
"github.com/oaswrap/spec/option"
)
func main() {
// Create a new OpenAPI router
r := spec.NewRouter(
option.WithTitle("My API"),
option.WithVersion("1.0.0"),
option.WithServer("https://api.example.com"),
option.WithSecurity("bearerAuth", option.SecurityHTTPBearer("Bearer")),
)
// Add routes
v1 := r.Group("/api/v1")
v1.Post("/login",
option.Summary("User login"),
option.Request(new(LoginRequest)),
option.Response(200, new(LoginResponse)),
)
auth := v1.Group("/", option.GroupSecurity("bearerAuth"))
auth.Get("/users/{id}",
option.Summary("Get user by ID"),
option.Request(new(GetUserRequest)),
option.Response(200, new(User)),
)
// Generate OpenAPI spec
if err := r.WriteSchemaTo("openapi.yaml"); err != nil {
log.Fatal(err)
}
log.Println("✅ OpenAPI spec generated at openapi.yaml")
}
type LoginRequest struct {
Username string `json:"username" required:"true"`
Password string `json:"password" required:"true"`
}
type LoginResponse struct {
Token string `json:"token"`
}
type GetUserRequest struct {
ID string `path:"id" required:"true"`
}
type User struct {
ID string `json:"id"`
Name string `json:"name"`
}📖 View the generated spec on Rest.Wiki
For seamless HTTP server integration, use one of our framework adapters:
| Framework | Package |
|---|---|
| Chi | chiopenapi |
| Echo | echoopenapi |
| Gin | ginopenapi |
| Fiber | fiberopenapi |
| HTTP | httpopenapi |
| Mux | muxopenapi |
| HTTPRouter | httprouteropenapi |
Each adapter provides:
- ✅ Automatic spec generation from your routes
- 📚 Built-in documentation UI at
/docs - 📄 YAML spec endpoints at
/docs/openapi.yaml - 🔧 Inline OpenAPI options with route definitions
Visit the individual adapter repositories for framework-specific examples and detailed integration guides.
- Generate OpenAPI files at build time
- Integrate with CI/CD pipelines
- Build custom documentation tools
- Need static spec generation
- Want automatic spec generation from routes
- Need zero-configuration setup
- Prefer inline OpenAPI configuration
- Want route registration + documentation in one step
The option package provides comprehensive OpenAPI configuration:
option.WithOpenAPIVersion("3.0.3") // Default: "3.0.3"
option.WithTitle("My API")
option.WithDescription("API description")
option.WithVersion("1.2.3")
option.WithContact(openapi.Contact{
Name: "Support Team",
URL: "https://support.example.com",
Email: "support@example.com",
})
option.WithLicense(openapi.License{
Name: "MIT License",
URL: "https://opensource.org/licenses/MIT",
})
option.WithExternalDocs("https://docs.example.com", "API Documentation")
option.WithTags(
openapi.Tag{
Name: "User Management",
Description: "Operations related to user management",
},
openapi.Tag{
Name: "Authentication",
Description: "Authentication related operations",
},
)option.WithServer("https://api.example.com")
option.WithServer("https://api-example.com/{version}",
option.ServerDescription("Production Server"),
option.ServerVariables(map[string]openapi.ServerVariable{
"version": {
Default: "v1",
Enum: []string{"v1", "v2"},
Description: "API version",
},
}),
)// Bearer token
option.WithSecurity("bearerAuth", option.SecurityHTTPBearer("Bearer"))
// API Key
option.WithSecurity("apiKey", option.SecurityAPIKey("X-API-Key", "header"))
// OAuth2
option.WithSecurity("oauth2", option.SecurityOAuth2(
openapi.OAuthFlows{
Implicit: &openapi.OAuthFlowsImplicit{
AuthorizationURL: "https://auth.example.com/authorize",
Scopes: map[string]string{
"read": "Read access",
"write": "Write access",
},
},
},
))option.OperationID("getUserByID") // Unique operation ID
option.Summary("Short description") // Brief summary
option.Description("Detailed description") // Full description
option.Tags("User Management", "Authentication") // Group by tags
option.Request(new(RequestModel)) // Request body model
option.Response(200, new(ResponseModel), // Response model
option.ContentDescription("Successful response"),
option.ContentType("application/json"),
option.ContentDefault(true),
)
option.Security("bearerAuth") // Apply security scheme
option.Deprecated() // Mark as deprecated
option.Hidden() // Hide from specDefine parameters using struct tags in your request models:
type GetUserRequest struct {
ID string `path:"id" required:"true" description:"User identifier"`
Limit int `query:"limit" description:"Maximum number of results"`
APIKey string `header:"X-API-Key" description:"API authentication key"`
}Apply settings to all routes within a group:
// Apply to all routes in the group
adminGroup := r.Group("/admin",
option.GroupTags("Administration"),
option.GroupSecurity("bearerAuth"),
option.GroupDeprecated(),
)
// Hide internal routes from documentation
internalGroup := r.Group("/internal",
option.GroupHidden(),
)type CreateUserRequest struct {
Name string `json:"name" required:"true" minLength:"2" maxLength:"50"`
Email string `json:"email" required:"true" format:"email"`
Age int `json:"age" minimum:"18" maximum:"120"`
Tags []string `json:"tags" maxItems:"10"`
}For comprehensive struct tag documentation, see swaggest/openapi-go and swaggest/jsonschema-go.
type APIResponse[T any] struct {
Success bool `json:"success"`
Data T `json:"data,omitempty"`
Error string `json:"error,omitempty"`
Timestamp string `json:"timestamp"`
}
// Usage
option.Response(200, new(APIResponse[User]))
option.Response(200, new(APIResponse[[]Product]))Explore complete working examples in the examples/ directory:
- Basic — Standalone spec generation
- Basic-HTTP — Built-in HTTP server with OpenAPI docs
- Petstore — Full Petstore API with routes and models
Complete documentation at pkg.go.dev/github.com/oaswrap/spec.
Key packages:
Q: Can I use this with my existing API?
A: Absolutely! Use the standalone version to document existing APIs, or gradually migrate to framework adapters.
Q: How does this compare to swag/swaggo?
A: While swag uses code comments, oaswrap uses pure Go code for type safety and better IDE support. Both have their merits - swag is annotation-based while oaswrap is code-first.
Q: How does this compare to Huma?
A: Both are excellent choices with different philosophies:
- Huma is a complete HTTP framework with built-in OpenAPI generation, validation, and middleware
- oaswrap/spec is a lightweight, framework-agnostic documentation builder that works with your existing setup
- Use Huma if you're building a new API and want an all-in-one solution with automatic validation
- Use oaswrap if you have existing code, prefer framework flexibility, or need standalone spec generation
Q: Is this production ready?
A: The library is in active development. While core functionality is solid, consider it beta software. Thorough testing is recommended before production use.
Q: How do I handle authentication in the generated docs?
A: Define security schemes using option.WithSecurity() and apply them to routes with option.Security(). The generated docs will include authentication UI.
We welcome contributions! Here's how you can help:
- 🐛 Report bugs — Open an issue with reproduction steps
- 💡 Suggest features — Share your ideas for improvements
- 📝 Improve docs — Help make our documentation clearer
- 🔧 Submit PRs — Fix bugs or add features
Please check existing issues and discussions before starting work on new features.