feat(server): API relay gateway backend M0-M4
Gin + GORM + pure-Go SQLite. Users/auth (JWT), API key management with quotas, proxy gateway with weighted channel failover and health checks, usage/billing ledger, cross-protocol conversion (Anthropic Messages / OpenAI Chat Completions / OpenAI Responses), and channel/model admin API. Channels declare native API formats and auto-convert the rest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b0c7439c01
commit
d0e31b198f
@@ -0,0 +1,42 @@
|
||||
package httpx
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// APIError is the standard error body for the management API.
|
||||
type APIError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// OK writes a JSON success response.
|
||||
func OK(c *gin.Context, data any) {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "data": data})
|
||||
}
|
||||
|
||||
// Created writes a 201 response.
|
||||
func Created(c *gin.Context, data any) {
|
||||
c.JSON(http.StatusCreated, gin.H{"code": 0, "data": data})
|
||||
}
|
||||
|
||||
// Fail writes an error response with the given status.
|
||||
func Fail(c *gin.Context, status int, message string) {
|
||||
c.AbortWithStatusJSON(status, gin.H{"code": status, "message": message})
|
||||
}
|
||||
|
||||
// FailWithCode writes an error with a custom business code.
|
||||
func FailWithCode(c *gin.Context, status, code int, message string) {
|
||||
c.AbortWithStatusJSON(status, gin.H{"code": code, "message": message})
|
||||
}
|
||||
|
||||
// Bind parses the JSON body and aborts with 400 on failure.
|
||||
func Bind(c *gin.Context, dst any) bool {
|
||||
if err := c.ShouldBindJSON(dst); err != nil {
|
||||
Fail(c, http.StatusBadRequest, "invalid request body: "+err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user