- 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.
87 lines
1.9 KiB
Go
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
|
|
}
|