yao/service/dynamic.go
Max 787954f0af Enhance OpenAPI Integration and API Routing
- Introduced support for OpenAPI mode, allowing dynamic routing and OAuth guards for API endpoints.
- Updated API root path handling to accommodate OpenAPI configurations, ensuring consistent URL structures.
- Added well-known routes for Yao metadata and OAuth discovery, improving API discoverability.
- Refactored middleware and guards to streamline OpenAPI integration, enhancing overall service functionality.
- Removed deprecated agent TypeScript file, simplifying the codebase and improving maintainability.
2026-01-04 15:46:09 +08:00

87 lines
1.9 KiB
Go

package service
import (
"fmt"
"strings"
"github.com/gin-gonic/gin"
"github.com/yaoapp/gou/api"
)
// DynamicAPIHandler is a dynamic API proxy handler that dispatches requests
// to the appropriate handler based on the route table.
// This enables hot-reloading of API definitions without server restart.
func DynamicAPIHandler(c *gin.Context) {
path := c.Param("path")
method := c.Request.Method
// Ensure path starts with /
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
// Find handler from route table
apiDef, pathDef, handler, params, err := api.FindHandler(method, path)
if err != nil {
c.JSON(404, gin.H{"code": 404, "message": "API not found"})
c.Abort()
return
}
// Set path parameters to gin.Context
for key, value := range params {
c.Params = append(c.Params, gin.Param{Key: key, Value: value})
}
// Apply guard
guard := pathDef.Guard
if guard == "" {
guard = apiDef.HTTP.Guard
}
if guard != "" && guard != "-" {
if err := applyGuard(c, guard); err != nil {
return // Guard already handled the response
}
}
// Execute the actual handler
handler(c)
}
// applyGuard applies the guard middleware(s) to the request
func applyGuard(c *gin.Context, guardName string) error {
guards := strings.Split(guardName, ",")
for _, name := range guards {
name = strings.TrimSpace(name)
if name == "" || name == "-" {
continue
}
// Get guard from HTTPGuards (set at Start time)
if handler, has := api.HTTPGuards[name]; has {
handler(c)
if c.IsAborted() {
return fmt.Errorf("guard aborted")
}
continue
}
// Custom guard via process
api.ProcessGuard(name)(c)
if c.IsAborted() {
return fmt.Errorf("guard aborted")
}
}
return nil
}
// ReloadAPIs reloads all API definitions from the apis directory
// This function is thread-safe and can be called at runtime
func ReloadAPIs() error {
err := api.ReloadAPIs("apis")
if err != nil {
return err
}
return nil
}