Files
cryptoHermes/internal/controller/restapi/v1/market_routes.go
dela 05dc2ef0e7 refactor: 去掉 GetDerivatives 的假 error 返回 + 同步 API 文档
GetDerivatives 签名里的 error 返回永远是 nil,controller 那段 if err != nil
是死分支,会误导调用方以为存在"全失败"语义。当前产品策略是 best-effort
response:局部失败 → warnings,bundle 永远非 nil,HTTP 永远 200。
等 Hermes 上游真要求"全失败 → 5xx"时再重新引入 error 返回。

同时把 docs/dev.md §13.5 示例补上 warnings 字段(上次重构遗漏的文档同步)。
2026-05-24 17:57:08 +08:00

91 lines
2.5 KiB
Go

package v1
import (
"strconv"
"strings"
"github.com/gofiber/fiber/v2"
"cryptoHermes/internal/usecase"
)
type MarketDeps struct {
MarketContext *usecase.MarketContextUsecase
MarketQuery *usecase.MarketQueryUsecase
MarketData usecase.MarketDataProvider
KlineRepo usecase.KlineRepository
}
var allowedIntervals = map[string]bool{
"15m": true, "1h": true, "4h": true, "1d": true, "1w": true,
}
func RegisterMarket(r fiber.Router, d MarketDeps) {
g := r.Group("/market")
g.Get("/context", func(c *fiber.Ctx) error {
symbol := strings.ToUpper(c.Query("symbol"))
if symbol == "" {
return fiber.NewError(fiber.StatusBadRequest, "symbol is required")
}
out, err := d.MarketContext.Build(c.UserContext(), symbol)
if err != nil && out == nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
return c.JSON(out)
})
g.Get("/klines", func(c *fiber.Ctx) error {
symbol := strings.ToUpper(c.Query("symbol"))
interval := c.Query("interval")
if symbol == "" || interval == "" {
return fiber.NewError(fiber.StatusBadRequest, "symbol and interval are required")
}
if !allowedIntervals[interval] {
return fiber.NewError(fiber.StatusBadRequest, "interval must be one of 15m/1h/4h/1d/1w")
}
limit := 300
if l := c.Query("limit"); l != "" {
if v, err := strconv.Atoi(l); err == nil && v > 0 && v <= 1000 {
limit = v
}
}
rows, err := d.KlineRepo.FindRecent(c.UserContext(), symbol, interval, limit)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.JSON(rows)
})
g.Get("/snapshot", func(c *fiber.Ctx) error {
symbol := strings.ToUpper(c.Query("symbol"))
if symbol == "" {
return fiber.NewError(fiber.StatusBadRequest, "symbol is required")
}
t, err := d.MarketData.GetTicker24h(c.UserContext(), symbol)
if err != nil {
return fiber.NewError(fiber.StatusBadGateway, err.Error())
}
return c.JSON(t)
})
g.Get("/derivatives", func(c *fiber.Ctx) error {
symbol := strings.ToUpper(c.Query("symbol"))
period := c.Query("period", "1h")
if symbol == "" {
return fiber.NewError(fiber.StatusBadRequest, "symbol is required")
}
bundle, warnings := d.MarketQuery.GetDerivatives(c.UserContext(), symbol, period)
return c.JSON(fiber.Map{
"symbol": symbol,
"funding": bundle.Funding,
"openInterest": bundle.OpenInterest,
"longShortRatio": bundle.LongShortRatio,
"takerBuySellVolume": bundle.TakerBuySellVolume,
"warnings": warnings,
})
})
}