Files
crawlab/core/openapi/wrapper.go
Marvin Zhang d6badb533d feat: enhance API routing and OpenAPI documentation support
- Introduced a new OpenAPI wrapper using Fizz for improved API documentation
- Refactored base controller to support more flexible route handling
- Added dynamic route registration with OpenAPI metadata
- Implemented generic response types for consistent API responses
- Updated router initialization to support OpenAPI documentation endpoint
- Improved route and resource naming utilities
- Migrated existing controllers to use new routing and response mechanisms
2025-03-11 23:45:06 +08:00

117 lines
2.9 KiB
Go

package openapi
import (
"fmt"
"github.com/loopfz/gadgeto/tonic"
"github.com/gin-gonic/gin"
"github.com/wI2L/fizz"
)
// FizzWrapper wraps an existing Gin Engine to add OpenAPI functionality
type FizzWrapper struct {
fizz *fizz.Fizz
gin *gin.Engine
}
// NewFizzWrapper creates a new wrapper around an existing Gin Engine
// This approach ensures we don't break existing functionality
func NewFizzWrapper(engine *gin.Engine) *FizzWrapper {
// Create a new Fizz instance using the existing Gin engine
f := fizz.NewFromEngine(engine)
return &FizzWrapper{
fizz: f,
gin: engine,
}
}
// GetFizz returns the underlying Fizz instance
func (w *FizzWrapper) GetFizz() *fizz.Fizz {
return w.fizz
}
// GetGin returns the underlying Gin engine
func (w *FizzWrapper) GetGin() *gin.Engine {
return w.gin
}
// Response represents an OpenAPI response
type Response struct {
Description string
Model interface{}
}
// RegisterRoute registers a route with OpenAPI documentation
func (w *FizzWrapper) RegisterRoute(method, path string, handler interface{}, id, summary, description string, responses map[int]Response) {
// Build operation options for OpenAPI documentation
opts := w.buildOperationOptions(id, summary, description, responses)
// Register the route with OpenAPI documentation
switch method {
case "GET":
w.fizz.GET(path, opts, tonic.Handler(handler, 200))
case "POST":
w.fizz.POST(path, opts, tonic.Handler(handler, 200))
case "PUT":
w.fizz.PUT(path, opts, tonic.Handler(handler, 200))
case "DELETE":
w.fizz.DELETE(path, opts, tonic.Handler(handler, 200))
case "PATCH":
w.fizz.PATCH(path, opts, tonic.Handler(handler, 200))
case "HEAD":
w.fizz.HEAD(path, opts, tonic.Handler(handler, 200))
case "OPTIONS":
w.fizz.OPTIONS(path, opts, tonic.Handler(handler, 200))
}
}
// BuildModelResponse builds a standard response model with a specific data type
func (w *FizzWrapper) BuildModelResponse() map[int]Response {
return map[int]Response{
400: {
Description: "Bad Request",
},
401: {
Description: "Unauthorized",
},
500: {
Description: "Internal Server Error",
},
}
}
// buildOperationOptions builds the options for a Fizz operation
func (w *FizzWrapper) buildOperationOptions(id, summary, description string, responses map[int]Response) []fizz.OperationOption {
var opts []fizz.OperationOption
// Add ID
if id != "" {
opts = append(opts, fizz.ID(id))
}
// Add summary
if summary != "" {
opts = append(opts, fizz.Summary(summary))
}
// Add description
if description != "" {
opts = append(opts, fizz.Description(description))
}
// Add responses
if responses != nil {
for status, response := range responses {
if response.Model != nil {
opts = append(opts, fizz.Response(fmt.Sprintf("%d", status), response.Description, response.Model, nil, nil))
} else {
opts = append(opts, fizz.Response(fmt.Sprintf("%d", status), response.Description, nil, nil, nil))
}
}
}
return opts
}