Add OpenAPI support and enhance configuration handling
- Integrated OpenAPI loading functionality into the engine's Load and Reload processes, allowing for better API management. - Updated the OpenAPI configuration to set a default BaseURL and ensure it does not have a trailing slash. - Implemented the Attach method to connect the OpenAPI server to the Gin router, facilitating API endpoint management. - Removed the obsolete hello package to streamline the OpenAPI module.
This commit is contained in:
parent
0fff602c93
commit
b96a400869
9 changed files with 348 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/yaoapp/yao/moapi"
|
"github.com/yaoapp/yao/moapi"
|
||||||
"github.com/yaoapp/yao/model"
|
"github.com/yaoapp/yao/model"
|
||||||
"github.com/yaoapp/yao/neo"
|
"github.com/yaoapp/yao/neo"
|
||||||
|
"github.com/yaoapp/yao/openapi"
|
||||||
"github.com/yaoapp/yao/pack"
|
"github.com/yaoapp/yao/pack"
|
||||||
"github.com/yaoapp/yao/pipe"
|
"github.com/yaoapp/yao/pipe"
|
||||||
"github.com/yaoapp/yao/plugin"
|
"github.com/yaoapp/yao/plugin"
|
||||||
|
|
@ -279,6 +280,13 @@ func Load(cfg config.Config, options LoadOption) (warnings []Warning, err error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load OpenAPI
|
||||||
|
_, err = openapi.Load(cfg)
|
||||||
|
if err != nil {
|
||||||
|
// printErr(cfg.Mode, "OpenAPI", err)
|
||||||
|
warnings = append(warnings, Warning{Widget: "OpenAPI", Error: err})
|
||||||
|
}
|
||||||
|
|
||||||
// Execute AfterLoad Process if exists
|
// Execute AfterLoad Process if exists
|
||||||
if share.App.AfterLoad != "" && !options.IgnoredAfterLoad {
|
if share.App.AfterLoad != "" && !options.IgnoredAfterLoad {
|
||||||
p, err := process.Of(share.App.AfterLoad, options)
|
p, err := process.Of(share.App.AfterLoad, options)
|
||||||
|
|
@ -468,6 +476,12 @@ func Reload(cfg config.Config, options LoadOption) (err error) {
|
||||||
printErr(cfg.Mode, "Neo", err)
|
printErr(cfg.Mode, "Neo", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load OpenAPI
|
||||||
|
_, err = openapi.Load(cfg)
|
||||||
|
if err != nil {
|
||||||
|
printErr(cfg.Mode, "OpenAPI", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Execute AfterLoad Process if exists
|
// Execute AfterLoad Process if exists
|
||||||
if share.App.AfterLoad != "" && !options.IgnoredAfterLoad {
|
if share.App.AfterLoad != "" && !options.IgnoredAfterLoad {
|
||||||
options.IsReload = true
|
options.IsReload = true
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,13 @@ func (config *Config) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set defaults if needed
|
// Set defaults if needed
|
||||||
|
if config.BaseURL == "" {
|
||||||
|
config.BaseURL = "/v1"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the BaseURL should not have trailing slash
|
||||||
|
config.BaseURL = strings.TrimSuffix(config.BaseURL, "/")
|
||||||
|
|
||||||
if config.Cache == "" {
|
if config.Cache == "" {
|
||||||
config.Cache = "__yao.oauth.cache"
|
config.Cache = "__yao.oauth.cache"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
140
openapi/docs/oauth.md
Normal file
140
openapi/docs/oauth.md
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
# OAuth 2.0/2.1 Route Mapping (RFC Standards + MCP Protocol Support)
|
||||||
|
|
||||||
|
## OAuth Core Endpoints (OAuth 2.1 Required)
|
||||||
|
|
||||||
|
| Endpoint | HTTP Method | Purpose | RFC Standard | MCP Requirement |
|
||||||
|
| ------------------- | ----------- | ------------------------------------------------ | ----------------------- | --------------------- |
|
||||||
|
| `/oauth/authorize` | GET, POST | Authorization request, obtain authorization code | RFC 6749 Section 3.1 | ✅ Required |
|
||||||
|
| `/oauth/token` | POST | Token request, exchange for access token | RFC 6749 Section 3.2 | ✅ Required |
|
||||||
|
| `/oauth/revoke` | POST | Revoke access token or refresh token | RFC 7009 | ✅ Required |
|
||||||
|
| `/oauth/introspect` | POST | Check token status and metadata | RFC 7662 | ✅ Recommended |
|
||||||
|
| `/oauth/jwks` | GET | JSON Web Key Set for token verification | RFC 7517 | ✅ Required (for JWT) |
|
||||||
|
| `/oauth/userinfo` | GET, POST | Retrieve user information | OpenID Connect Core 1.0 | ✅ Recommended |
|
||||||
|
|
||||||
|
## OAuth Extended Endpoints
|
||||||
|
|
||||||
|
| Endpoint | HTTP Method | Purpose | RFC Standard | MCP Requirement |
|
||||||
|
| ----------------------------- | ----------- | ----------------------------- | ------------ | --------------- |
|
||||||
|
| `/oauth/register` | POST | Dynamic client registration | RFC 7591 | ✅ Required |
|
||||||
|
| `/oauth/register/:client_id` | GET | Retrieve client configuration | RFC 7592 | ✅ Optional |
|
||||||
|
| `/oauth/register/:client_id` | PUT | Update client configuration | RFC 7592 | ✅ Optional |
|
||||||
|
| `/oauth/register/:client_id` | DELETE | Delete client configuration | RFC 7592 | ✅ Optional |
|
||||||
|
| `/oauth/device_authorization` | POST | Device authorization flow | RFC 8628 | ✅ Optional |
|
||||||
|
| `/oauth/par` | POST | Pushed Authorization Request | RFC 9126 | ✅ Recommended |
|
||||||
|
| `/oauth/token_exchange` | POST | Token exchange | RFC 8693 | ✅ Optional |
|
||||||
|
|
||||||
|
## Discovery and Metadata Endpoints
|
||||||
|
|
||||||
|
| Endpoint | HTTP Method | Purpose | RFC Standard | MCP Requirement |
|
||||||
|
| ----------------------------------------- | ----------- | ----------------------------- | ---------------------------- | --------------- |
|
||||||
|
| `/.well-known/oauth-authorization-server` | GET | Authorization server metadata | RFC 8414 | ✅ Required |
|
||||||
|
| `/.well-known/openid_configuration` | GET | OpenID Connect configuration | OpenID Connect Discovery 1.0 | ✅ Optional |
|
||||||
|
| `/.well-known/oauth-protected-resource` | GET | Protected resource metadata | RFC 9728 | ✅ Required |
|
||||||
|
|
||||||
|
## Interface Method Mapping
|
||||||
|
|
||||||
|
Each route handler corresponds to interface methods:
|
||||||
|
|
||||||
|
- `oauthAuthorize` → `OAuth.Authorize()`
|
||||||
|
- `oauthToken` → `OAuth.Token()`, `OAuth.RefreshToken()`
|
||||||
|
- `oauthRevoke` → `OAuth.Revoke()`
|
||||||
|
- `oauthIntrospect` → `OAuth.Introspect()`
|
||||||
|
- `oauthJWKS` → `OAuth.JWKS()`
|
||||||
|
- `oauthUserInfo` → `OAuth.UserInfo()`
|
||||||
|
- `oauthRegister` → `OAuth.Register()`, `OAuth.DynamicClientRegistration()`
|
||||||
|
- `oauthGetClient` → Client query methods
|
||||||
|
- `oauthUpdateClient` → `OAuth.UpdateClient()`
|
||||||
|
- `oauthDeleteClient` → `OAuth.DeleteClient()`
|
||||||
|
- `oauthDeviceAuthorization` → `OAuth.DeviceAuthorization()`
|
||||||
|
- `oauthPushedAuthorizationRequest` → `OAuth.PushAuthorizationRequest()`
|
||||||
|
- `oauthTokenExchange` → `OAuth.TokenExchange()`
|
||||||
|
- `oauthServerMetadata` → `OAuth.GetServerMetadata()`
|
||||||
|
- `oauthProtectedResourceMetadata` → `OAuth.GetProtectedResourceMetadata()`
|
||||||
|
|
||||||
|
## MCP Protocol Special Requirements
|
||||||
|
|
||||||
|
1. **Resource Parameter Validation**: Using `OAuth.ValidateResourceParameter()`
|
||||||
|
2. **Canonical Resource URI**: Using `OAuth.GetCanonicalResourceURI()`
|
||||||
|
3. **State Parameter Security**: Using `OAuth.ValidateStateParameter()`, `OAuth.GenerateStateParameter()`
|
||||||
|
4. **Redirect URI Validation**: Using `OAuth.ValidateRedirectURI()`
|
||||||
|
5. **Token Binding**: Using `OAuth.ValidateTokenBinding()`
|
||||||
|
6. **Refresh Token Rotation**: Using `OAuth.RotateRefreshToken()`
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- All POST endpoints should validate CSRF protection
|
||||||
|
- `/oauth/authorize` supports both GET and POST, but POST is recommended for enhanced security
|
||||||
|
- PKCE (Proof Key for Code Exchange) should be enforced in all authorization code flows
|
||||||
|
- All endpoints should support HTTPS
|
||||||
|
- Token endpoints require client authentication
|
||||||
|
- State parameters are required in authorization flows
|
||||||
|
|
||||||
|
## Typical Flows
|
||||||
|
|
||||||
|
1. **Authorization Code Flow**: `/oauth/authorize` → `/oauth/token`
|
||||||
|
2. **Refresh Token**: `/oauth/token` (grant_type=refresh_token)
|
||||||
|
3. **Token Revocation**: `/oauth/revoke`
|
||||||
|
4. **Device Flow**: `/oauth/device_authorization` → `/oauth/token`
|
||||||
|
5. **Token Introspection**: `/oauth/introspect`
|
||||||
|
6. **Dynamic Registration**: `/oauth/register`
|
||||||
|
|
||||||
|
## MCP Authorization Flow Overview
|
||||||
|
|
||||||
|
The Model Context Protocol requires specific OAuth 2.1 implementation patterns:
|
||||||
|
|
||||||
|
### Authorization Server Discovery
|
||||||
|
|
||||||
|
1. **Protected Resource Metadata**: MCP servers MUST implement RFC 9728
|
||||||
|
2. **WWW-Authenticate Header**: Used in 401 responses to indicate authorization server location
|
||||||
|
3. **Server Metadata**: Authorization servers MUST provide RFC 8414 metadata
|
||||||
|
|
||||||
|
### Resource Parameter Implementation
|
||||||
|
|
||||||
|
MCP clients MUST implement Resource Indicators (RFC 8707):
|
||||||
|
|
||||||
|
```
|
||||||
|
&resource=https%3A%2F%2Fmcp.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
- MUST be included in both authorization and token requests
|
||||||
|
- MUST identify the target MCP server
|
||||||
|
- MUST use canonical URI format
|
||||||
|
|
||||||
|
### Canonical Server URI Examples
|
||||||
|
|
||||||
|
**Valid canonical URIs:**
|
||||||
|
|
||||||
|
- `https://mcp.example.com/mcp`
|
||||||
|
- `https://mcp.example.com`
|
||||||
|
- `https://mcp.example.com:8443`
|
||||||
|
- `https://mcp.example.com/server/mcp`
|
||||||
|
|
||||||
|
**Invalid canonical URIs:**
|
||||||
|
|
||||||
|
- `mcp.example.com` (missing scheme)
|
||||||
|
- `https://mcp.example.com#fragment` (contains fragment)
|
||||||
|
|
||||||
|
### Access Token Usage
|
||||||
|
|
||||||
|
- MUST use Authorization header: `Authorization: Bearer <access-token>`
|
||||||
|
- MUST NOT include tokens in URI query strings
|
||||||
|
- MUST validate token audience binding
|
||||||
|
- MUST implement token theft protection
|
||||||
|
|
||||||
|
### Dynamic Client Registration
|
||||||
|
|
||||||
|
Authorization servers SHOULD support RFC 7591 for seamless client onboarding:
|
||||||
|
|
||||||
|
- Enables automatic registration with new authorization servers
|
||||||
|
- Reduces user friction
|
||||||
|
- Allows authorization servers to implement custom registration policies
|
||||||
|
|
||||||
|
### Security Requirements
|
||||||
|
|
||||||
|
1. **Token Audience Binding**: Tokens MUST be bound to intended audiences
|
||||||
|
2. **Communication Security**: All endpoints MUST use HTTPS
|
||||||
|
3. **PKCE Protection**: MUST implement PKCE for authorization code flows
|
||||||
|
4. **Open Redirection Prevention**: MUST validate redirect URIs exactly
|
||||||
|
5. **Refresh Token Rotation**: MUST rotate refresh tokens for public clients
|
||||||
|
|
||||||
|
This route planning follows OAuth 2.1 best practices, supports all MCP protocol requirements, and provides complete OAuth authorization server functionality with enhanced security measures specifically designed for Model Context Protocol implementations.
|
||||||
35
openapi/hello.go
Normal file
35
openapi/hello.go
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
package openapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/yao/share"
|
||||||
|
)
|
||||||
|
|
||||||
|
// attachHelloWorld attaches the hello world handlers to the router
|
||||||
|
func (openapi *OpenAPI) attachHelloWorld(base *gin.RouterGroup) {
|
||||||
|
|
||||||
|
// hello handlers
|
||||||
|
hello := base.Group("/helloworld")
|
||||||
|
|
||||||
|
// Health check
|
||||||
|
hello.GET("/hello", openapi.helloWorldHello)
|
||||||
|
hello.POST("/hello", openapi.helloWorldHello)
|
||||||
|
}
|
||||||
|
|
||||||
|
// helloWorldHello is the handler for the hello world endpoint
|
||||||
|
func (openapi *OpenAPI) helloWorldHello(c *gin.Context) {
|
||||||
|
serverTime := time.Now().Format(time.RFC3339)
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"MESSAGE": "HELLO, WORLD",
|
||||||
|
"SERVER_TIME": serverTime,
|
||||||
|
"VERSION": share.VERSION,
|
||||||
|
"PRVERSION": share.PRVERSION,
|
||||||
|
"CUI": share.CUI,
|
||||||
|
"PRCUI": share.PRCUI,
|
||||||
|
"APP": share.App.Name,
|
||||||
|
"APP_VERSION": share.App.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package hello
|
|
||||||
115
openapi/oauth.go
Normal file
115
openapi/oauth.go
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package openapi
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
// OAuth handlers
|
||||||
|
func (openapi *OpenAPI) attachOAuth(base *gin.RouterGroup) {
|
||||||
|
|
||||||
|
// OAuth Core Endpoints (RFC 6749, OAuth 2.1)
|
||||||
|
oauth := base.Group("/oauth")
|
||||||
|
|
||||||
|
// Authorization endpoint - RFC 6749 Section 3.1
|
||||||
|
oauth.GET("/authorize", openapi.oauthAuthorize)
|
||||||
|
oauth.POST("/authorize", openapi.oauthAuthorize) // Support both GET and POST
|
||||||
|
|
||||||
|
// Token endpoint - RFC 6749 Section 3.2
|
||||||
|
oauth.POST("/token", openapi.oauthToken)
|
||||||
|
|
||||||
|
// Token revocation endpoint - RFC 7009
|
||||||
|
oauth.POST("/revoke", openapi.oauthRevoke)
|
||||||
|
|
||||||
|
// Token introspection endpoint - RFC 7662
|
||||||
|
oauth.POST("/introspect", openapi.oauthIntrospect)
|
||||||
|
|
||||||
|
// JSON Web Key Set endpoint - RFC 7517
|
||||||
|
oauth.GET("/jwks", openapi.oauthJWKS)
|
||||||
|
|
||||||
|
// UserInfo endpoint - OpenID Connect Core 1.0
|
||||||
|
oauth.GET("/userinfo", openapi.oauthUserInfo)
|
||||||
|
oauth.POST("/userinfo", openapi.oauthUserInfo) // Support both GET and POST
|
||||||
|
|
||||||
|
// OAuth Extended Endpoints
|
||||||
|
// Dynamic Client Registration - RFC 7591 (Required by MCP)
|
||||||
|
oauth.POST("/register", openapi.oauthRegister)
|
||||||
|
|
||||||
|
// Client Configuration - RFC 7592
|
||||||
|
oauth.GET("/register/:client_id", openapi.oauthGetClient)
|
||||||
|
oauth.PUT("/register/:client_id", openapi.oauthUpdateClient)
|
||||||
|
oauth.DELETE("/register/:client_id", openapi.oauthDeleteClient)
|
||||||
|
|
||||||
|
// Device Authorization Flow - RFC 8628
|
||||||
|
oauth.POST("/device_authorization", openapi.oauthDeviceAuthorization)
|
||||||
|
|
||||||
|
// Pushed Authorization Request - RFC 9126
|
||||||
|
oauth.POST("/par", openapi.oauthPushedAuthorizationRequest)
|
||||||
|
|
||||||
|
// Token Exchange - RFC 8693
|
||||||
|
oauth.POST("/token_exchange", openapi.oauthTokenExchange)
|
||||||
|
|
||||||
|
// OAuth Discovery and Metadata Endpoints
|
||||||
|
wellKnown := base.Group("/.well-known")
|
||||||
|
|
||||||
|
// OAuth Authorization Server Metadata - RFC 8414 (Required by MCP)
|
||||||
|
wellKnown.GET("/oauth-authorization-server", openapi.oauthServerMetadata)
|
||||||
|
|
||||||
|
// OpenID Connect Discovery - OpenID Connect Discovery 1.0
|
||||||
|
wellKnown.GET("/openid_configuration", openapi.oauthOpenIDConfiguration)
|
||||||
|
|
||||||
|
// OAuth Protected Resource Metadata - RFC 9728 (Required by MCP)
|
||||||
|
wellKnown.GET("/oauth-protected-resource", openapi.oauthProtectedResourceMetadata)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth Core Endpoints Implementation
|
||||||
|
|
||||||
|
// oauthAuthorize handles authorization requests - RFC 6749 Section 3.1
|
||||||
|
func (openapi *OpenAPI) oauthAuthorize(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthToken handles token requests - RFC 6749 Section 3.2
|
||||||
|
func (openapi *OpenAPI) oauthToken(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthRevoke handles token revocation - RFC 7009
|
||||||
|
func (openapi *OpenAPI) oauthRevoke(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthIntrospect handles token introspection - RFC 7662
|
||||||
|
func (openapi *OpenAPI) oauthIntrospect(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthJWKS returns JSON Web Key Set - RFC 7517
|
||||||
|
func (openapi *OpenAPI) oauthJWKS(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthUserInfo returns user information - OpenID Connect Core 1.0
|
||||||
|
func (openapi *OpenAPI) oauthUserInfo(c *gin.Context) {}
|
||||||
|
|
||||||
|
// OAuth Extended Endpoints Implementation
|
||||||
|
|
||||||
|
// oauthRegister handles dynamic client registration - RFC 7591
|
||||||
|
func (openapi *OpenAPI) oauthRegister(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthGetClient retrieves client configuration - RFC 7592
|
||||||
|
func (openapi *OpenAPI) oauthGetClient(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthUpdateClient updates client configuration - RFC 7592
|
||||||
|
func (openapi *OpenAPI) oauthUpdateClient(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthDeleteClient deletes client configuration - RFC 7592
|
||||||
|
func (openapi *OpenAPI) oauthDeleteClient(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthDeviceAuthorization handles device authorization - RFC 8628
|
||||||
|
func (openapi *OpenAPI) oauthDeviceAuthorization(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthPushedAuthorizationRequest handles PAR - RFC 9126
|
||||||
|
func (openapi *OpenAPI) oauthPushedAuthorizationRequest(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthTokenExchange handles token exchange - RFC 8693
|
||||||
|
func (openapi *OpenAPI) oauthTokenExchange(c *gin.Context) {}
|
||||||
|
|
||||||
|
// OAuth Discovery and Metadata Endpoints Implementation
|
||||||
|
|
||||||
|
// oauthServerMetadata returns authorization server metadata - RFC 8414
|
||||||
|
func (openapi *OpenAPI) oauthServerMetadata(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthOpenIDConfiguration returns OpenID Connect configuration
|
||||||
|
func (openapi *OpenAPI) oauthOpenIDConfiguration(c *gin.Context) {}
|
||||||
|
|
||||||
|
// oauthProtectedResourceMetadata returns protected resource metadata - RFC 9728
|
||||||
|
func (openapi *OpenAPI) oauthProtectedResourceMetadata(c *gin.Context) {}
|
||||||
|
|
@ -3,6 +3,7 @@ package openapi
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yaoapp/gou/application"
|
"github.com/yaoapp/gou/application"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/openapi/oauth"
|
"github.com/yaoapp/yao/openapi/oauth"
|
||||||
|
|
@ -50,3 +51,24 @@ func Load(appConfig config.Config) (*OpenAPI, error) {
|
||||||
Server = &OpenAPI{Config: &config, OAuth: oauthService}
|
Server = &OpenAPI{Config: &config, OAuth: oauthService}
|
||||||
return Server, nil
|
return Server, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attach attaches the OpenAPI server to the router
|
||||||
|
func (openapi *OpenAPI) Attach(router *gin.Engine) {
|
||||||
|
|
||||||
|
// Ignore if the OpenAPI server is not configured
|
||||||
|
if openapi.Config == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic Groups
|
||||||
|
baseURL := openapi.Config.BaseURL
|
||||||
|
group := router.Group(baseURL)
|
||||||
|
|
||||||
|
// OAuth handlers
|
||||||
|
openapi.attachOAuth(group)
|
||||||
|
|
||||||
|
// Hello World handlers
|
||||||
|
openapi.attachHelloWorld(group)
|
||||||
|
|
||||||
|
// Custom handlers (Defined by developer)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
|
"github.com/yaoapp/yao/openapi"
|
||||||
"github.com/yaoapp/yao/share"
|
"github.com/yaoapp/yao/share"
|
||||||
"github.com/yaoapp/yao/sui/api"
|
"github.com/yaoapp/yao/sui/api"
|
||||||
)
|
)
|
||||||
|
|
@ -23,6 +24,14 @@ var Middlewares = []gin.HandlerFunc{
|
||||||
// withStaticFileServer static file server
|
// withStaticFileServer static file server
|
||||||
func withStaticFileServer(c *gin.Context) {
|
func withStaticFileServer(c *gin.Context) {
|
||||||
|
|
||||||
|
// Handle OpenAPI server
|
||||||
|
if openapi.Server != nil && openapi.Server.Config != nil && openapi.Server.Config.BaseURL != "" {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Path, openapi.Server.Config.BaseURL+"/") {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle API & websocket
|
// Handle API & websocket
|
||||||
length := len(c.Request.URL.Path)
|
length := len(c.Request.URL.Path)
|
||||||
if (length >= 5 && c.Request.URL.Path[0:5] == "/api/") ||
|
if (length >= 5 && c.Request.URL.Path[0:5] == "/api/") ||
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/yaoapp/gou/server/http"
|
"github.com/yaoapp/gou/server/http"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/neo"
|
"github.com/yaoapp/yao/neo"
|
||||||
|
"github.com/yaoapp/yao/openapi"
|
||||||
"github.com/yaoapp/yao/share"
|
"github.com/yaoapp/yao/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,6 +41,11 @@ func Start(cfg config.Config) (*http.Server, error) {
|
||||||
neo.Neo.API(router, "/api/__yao/neo")
|
neo.Neo.API(router, "/api/__yao/neo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenAPI Server
|
||||||
|
if openapi.Server != nil {
|
||||||
|
openapi.Server.Attach(router)
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err = srv.Start()
|
err = srv.Start()
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue