Co-authored-by: IvanX006 <ivan@bitechsystems.co.za> Co-authored-by: Warkanum <HEIN.PUTH@GMAIL.COM> Co-authored-by: Hein <hein@bitechsystems.co.za> |
||
|---|---|---|
| .. | ||
| example.go | ||
| generator_test.go | ||
| generator.go | ||
| paths.go | ||
| README.md | ||
| ui_handler_test.go | ||
| ui_handler.go | ||
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.