* Updated all instances of reflect.Ptr to reflect.Pointer for consistency in type checking.
OpenAPI Generator for ResolveSpec
This package provides automatic OpenAPI 3.0 specification generation for ResolveSpec, RestheadSpec, and FuncSpec API frameworks.
Features
- Automatic Schema Generation: Generates OpenAPI schemas from Go struct models
- Multiple Framework Support: Works with RestheadSpec, ResolveSpec, and FuncSpec
- Dynamic Endpoint Discovery: Automatically discovers all registered models and generates paths
- Query Parameter Access: Access spec via
?openapion any endpoint or via/openapi - Comprehensive Documentation: Includes all request/response schemas, parameters, and security schemes
Quick Start
RestheadSpec Example
import (
"github.com/bitechdev/ResolveSpec/pkg/openapi"
"github.com/bitechdev/ResolveSpec/pkg/restheadspec"
"github.com/gorilla/mux"
)
func main() {
// 1. Create handler
handler := restheadspec.NewHandlerWithGORM(db)
// 2. Register models
handler.registry.RegisterModel("public.users", User{})
handler.registry.RegisterModel("public.products", Product{})
// 3. Configure OpenAPI generator
handler.SetOpenAPIGenerator(func() (string, error) {
generator := openapi.NewGenerator(openapi.GeneratorConfig{
Title: "My API",
Description: "API documentation",
Version: "1.0.0",
BaseURL: "http://localhost:8080",
Registry: handler.registry.(*modelregistry.DefaultModelRegistry),
IncludeRestheadSpec: true,
IncludeResolveSpec: false,
IncludeFuncSpec: false,
})
return generator.GenerateJSON()
})
// 4. Setup routes (automatically includes /openapi endpoint)
router := mux.NewRouter()
restheadspec.SetupMuxRoutes(router, handler, nil)
// Start server
http.ListenAndServe(":8080", router)
}
ResolveSpec Example
func main() {
// 1. Create handler
handler := resolvespec.NewHandlerWithGORM(db)
// 2. Register models
handler.RegisterModel("public", "users", User{})
handler.RegisterModel("public", "products", Product{})
// 3. Configure OpenAPI generator
handler.SetOpenAPIGenerator(func() (string, error) {
generator := openapi.NewGenerator(openapi.GeneratorConfig{
Title: "My API",
Version: "1.0.0",
Registry: handler.registry.(*modelregistry.DefaultModelRegistry),
IncludeResolveSpec: true,
})
return generator.GenerateJSON()
})
// 4. Setup routes
router := mux.NewRouter()
resolvespec.SetupMuxRoutes(router, handler, nil)
http.ListenAndServe(":8080", router)
}
Accessing the OpenAPI Specification
Once configured, the OpenAPI spec is available in two ways:
1. Global /openapi Endpoint
curl http://localhost:8080/openapi
Returns the complete OpenAPI specification for all registered models.
2. Query Parameter on Any Endpoint
# RestheadSpec
curl http://localhost:8080/public/users?openapi
# ResolveSpec
curl http://localhost:8080/resolve/public/users?openapi
Returns the same OpenAPI specification as /openapi.
Generated Endpoints
RestheadSpec
For each registered model (e.g., public.users), the following paths are generated:
GET /public/users- List records with header-based filteringPOST /public/users- Create a new recordGET /public/users/{id}- Get a single recordPUT /public/users/{id}- Update a recordPATCH /public/users/{id}- Partially update a recordDELETE /public/users/{id}- Delete a recordGET /public/users/metadata- Get table metadataOPTIONS /public/users- CORS preflight
ResolveSpec
For each registered model (e.g., public.users), the following paths are generated:
POST /resolve/public/users- Execute operations (read, create, meta)POST /resolve/public/users/{id}- Execute operations (update, delete)GET /resolve/public/users- Get metadataOPTIONS /resolve/public/users- CORS preflight
Schema Generation
The generator automatically extracts information from your Go struct tags:
type User struct {
ID int `json:"id" gorm:"primaryKey" description:"User ID"`
Name string `json:"name" gorm:"not null" description:"User's full name"`
Email string `json:"email" gorm:"unique" description:"Email address"`
CreatedAt time.Time `json:"created_at" description:"Creation timestamp"`
Roles []string `json:"roles" description:"User roles"`
}
This generates an OpenAPI schema with:
- Property names from
jsontags - Required fields from
gorm:"not null"and non-pointer types - Descriptions from
descriptiontags - Proper type mappings (int → integer, time.Time → string with format: date-time, etc.)
RestheadSpec Headers
The generator documents all RestheadSpec HTTP headers:
X-Filters- JSON array of filter conditionsX-Columns- Comma-separated columns to selectX-Sort- JSON array of sort specificationsX-Limit- Maximum records to returnX-Offset- Records to skipX-Preload- Relations to eager loadX-Expand- Relations to expand (LEFT JOIN)X-Distinct- Enable DISTINCT queriesX-Response-Format- Response format (detail, simple, syncfusion)X-Clean-JSON- Remove null/empty fieldsX-Custom-SQL-Where- Custom WHERE clause (AND)X-Custom-SQL-Or- Custom WHERE clause (OR)
ResolveSpec Request Body
The generator documents the ResolveSpec request body structure:
{
"operation": "read",
"data": {},
"id": 123,
"options": {
"limit": 10,
"offset": 0,
"filters": [
{"column": "status", "operator": "eq", "value": "active"}
],
"sort": [
{"column": "created_at", "direction": "desc"}
]
}
}
Security Schemes
The generator automatically includes common security schemes:
- BearerAuth: JWT Bearer token authentication
- SessionToken: Session token in Authorization header
- CookieAuth: Cookie-based session authentication
- HeaderAuth: Header-based user authentication (X-User-ID)
FuncSpec Custom Endpoints
For FuncSpec, you can manually register custom SQL endpoints:
funcSpecEndpoints := map[string]openapi.FuncSpecEndpoint{
"/api/reports/sales": {
Path: "/api/reports/sales",
Method: "GET",
Summary: "Get sales report",
Description: "Returns sales data for specified date range",
SQLQuery: "SELECT * FROM sales WHERE date BETWEEN [start_date] AND [end_date]",
Parameters: []string{"start_date", "end_date"},
},
}
generator := openapi.NewGenerator(openapi.GeneratorConfig{
// ... other config
IncludeFuncSpec: true,
FuncSpecEndpoints: funcSpecEndpoints,
})
Combining Multiple Frameworks
You can generate a unified OpenAPI spec that includes multiple frameworks:
generator := openapi.NewGenerator(openapi.GeneratorConfig{
Title: "Unified API",
Version: "1.0.0",
Registry: sharedRegistry,
IncludeRestheadSpec: true,
IncludeResolveSpec: true,
IncludeFuncSpec: true,
FuncSpecEndpoints: funcSpecEndpoints,
})
This will generate a complete spec with all endpoints from all frameworks.
Advanced Customization
You can customize the generated spec further:
handler.SetOpenAPIGenerator(func() (string, error) {
generator := openapi.NewGenerator(config)
// Generate initial spec
spec, err := generator.Generate()
if err != nil {
return "", err
}
// Add contact information
spec.Info.Contact = &openapi.Contact{
Name: "API Support",
Email: "support@example.com",
URL: "https://example.com/support",
}
// Add additional servers
spec.Servers = append(spec.Servers, openapi.Server{
URL: "https://staging.example.com",
Description: "Staging Server",
})
// Convert back to JSON
data, _ := json.MarshalIndent(spec, "", " ")
return string(data), nil
})
Using the Built-in UI Handler
The package includes a built-in UI handler that serves popular OpenAPI visualization tools. No need to download or manage static files - everything is served from CDN.
Quick Start
import (
"github.com/bitechdev/ResolveSpec/pkg/openapi"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
// Setup your API routes and OpenAPI generator...
// (see examples above)
// Add the UI handler - defaults to Swagger UI
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.SwaggerUI,
SpecURL: "/openapi",
Title: "My API Documentation",
})
// Now visit http://localhost:8080/docs
http.ListenAndServe(":8080", router)
}
Supported UI Frameworks
The handler supports four popular OpenAPI UI frameworks:
1. Swagger UI (Default)
The most widely used OpenAPI UI with excellent compatibility and features.
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.SwaggerUI,
Theme: "dark", // optional: "light" or "dark"
})
2. RapiDoc
Modern, customizable, and feature-rich OpenAPI UI.
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.RapiDoc,
Theme: "dark",
})
3. Redoc
Clean, responsive documentation with great UX.
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.Redoc,
})
4. Scalar
Modern and sleek OpenAPI documentation.
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.Scalar,
Theme: "dark",
})
Configuration Options
type UIConfig struct {
UIType UIType // SwaggerUI, RapiDoc, Redoc, or Scalar
SpecURL string // URL to OpenAPI spec (default: "/openapi")
Title string // Page title (default: "API Documentation")
FaviconURL string // Custom favicon URL (optional)
CustomCSS string // Custom CSS to inject (optional)
Theme string // "light" or "dark" (support varies by UI)
}
Custom Styling Example
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.SwaggerUI,
Title: "Acme Corp API",
CustomCSS: `
.swagger-ui .topbar {
background-color: #1976d2;
}
.swagger-ui .info .title {
color: #1976d2;
}
`,
})
Using Multiple UIs
You can serve different UIs at different paths:
// Swagger UI at /docs
openapi.SetupUIRoute(router, "/docs", openapi.UIConfig{
UIType: openapi.SwaggerUI,
})
// Redoc at /redoc
openapi.SetupUIRoute(router, "/redoc", openapi.UIConfig{
UIType: openapi.Redoc,
})
// RapiDoc at /api-docs
openapi.SetupUIRoute(router, "/api-docs", openapi.UIConfig{
UIType: openapi.RapiDoc,
})
Manual Handler Usage
If you need more control, use the handler directly:
handler := openapi.UIHandler(openapi.UIConfig{
UIType: openapi.SwaggerUI,
SpecURL: "/api/openapi.json",
})
router.Handle("/documentation", handler)
Using with External Swagger UI
Alternatively, you can use an external Swagger UI instance:
- Get the spec from
/openapi - Load it in Swagger UI at
https://petstore.swagger.io/ - Or self-host Swagger UI and point it to your
/openapiendpoint
Testing
You can test the OpenAPI endpoint:
# Get the full spec
curl http://localhost:8080/openapi | jq
# Validate with openapi-generator
openapi-generator validate -i http://localhost:8080/openapi
# Generate client SDKs
openapi-generator generate -i http://localhost:8080/openapi -g typescript-fetch -o ./client
Complete Example
See example.go in this package for complete, runnable examples including:
- Basic RestheadSpec setup
- Basic ResolveSpec setup
- Combining both frameworks
- Adding FuncSpec endpoints
- Advanced customization
License
Part of the ResolveSpec project.