mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
更新示例
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: "new-api"
|
||||
description: "Wavelet 项目专用:当新增或修改自定义业务 API、新增业务路由、新增 service 层核心逻辑时必须使用。本技能指导包职责划分、推荐文件结构、路由解耦、Swagger 文档生成与质量门禁验证。"
|
||||
---
|
||||
|
||||
# 新增业务 API / 接口开发规范
|
||||
|
||||
本技能涵盖 Wavelet 的业务接口开发规范。开始开发前先阅读仓库根目录 [AGENTS.md](file:///Users/ryan/DEV/Go/Wavelet/AGENTS.md),遵守项目级核心规则。
|
||||
|
||||
为了保持核心路由入口的稳定性,**所有新增的定制业务接口路由统一注册在独立的 go 文件中,严禁直接堆叠到 `router.go`**。
|
||||
|
||||
---
|
||||
|
||||
## 包职责划分 (Package Responsibilities)
|
||||
|
||||
按照 Go 语言最佳实践与 Google 的开发风格,接口开发应该进行严格的分层,以避免循环依赖和逻辑混乱。
|
||||
|
||||
| 目录/包名 | 职责定位 | 框架依赖限制 | 常见包含内容 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`internal/router/`** | 路由分发层 | 依赖 Gin 框架 | `router.go` 核心路由、`custom.go` (自定义路由注册入口) |
|
||||
| **`internal/apps/custom/`** | 应用入口层与本地逻辑层 | 依赖 Gin 框架 (路由/Handler 部分) | 接收 HTTP 请求、解析请求体(JSON/Query)、校验基础参数、提取 Session。对于**模块内闭环的简单业务逻辑**,直接在其下的 `logics.go` 或 `*_logic.go` 中实现。 |
|
||||
| **`internal/service/`** | 核心跨模块业务服务层 | **禁止**依赖 Gin/HTTP 框架 | 仅存放**复杂、跨模块/跨领域交互,或被多端复用**(如同时被 Handler、后台 Asynq 任务、Cobra CLI 命令行调用)的业务核心逻辑。只接受 standard `context.Context`。 |
|
||||
| **`internal/model/`** | 数据模型层 | 依赖 GORM / SQL 基础 | GORM 实体定义、表结构、主键生成、单表极简 SQL 查询方法。 |
|
||||
| **`internal/db/`** | 数据存储层 | 依赖 SQL 驱动 / GORM 连接 | PostgreSQL, SQLite 等数据库连接管理与 Goose 数据库迁移文件。 |
|
||||
|
||||
---
|
||||
|
||||
## 建议创建/修改的文件结构
|
||||
|
||||
当新增一套定制的业务接口(例如名为 `custom` 的业务模块)时,根据逻辑复杂度建议采用以下文件结构:
|
||||
|
||||
```text
|
||||
internal/
|
||||
├── router/
|
||||
│ └── custom.go # [修改/创建] 仅用于注册定制路由,将路由委托给 apps/custom
|
||||
├── apps/
|
||||
│ └── custom/
|
||||
│ ├── routers.go # [新建] HTTP Handlers (Gin),负责参数绑定、校验与响应
|
||||
│ ├── logics.go # [新建] 承载模块内闭环的简单业务逻辑(保持该逻辑仅局限在当前模块)
|
||||
│ └── errs.go # [新建] 仅存放业务特有的错误常量定义(可选)
|
||||
└── service/
|
||||
└── custom.go # [新建/可选] 仅当出现跨模块交互、复杂多表事务或需要被 Task/CLI 复用时才创建
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心开发步骤 (Step-by-Step Flow)
|
||||
|
||||
### 步骤 1:如果有数据库变更,编写数据库迁移
|
||||
如果需要新表或字段,请参考 [database-migration](../database-migration/SKILL.md) 技能,在 `internal/db/migrator/goose/` 目录下编写迁移文件。在 `internal/model/` 中定义 GORM 数据模型。
|
||||
|
||||
### 步骤 2:判断业务逻辑的归属与放置
|
||||
在编写具体逻辑前,必须明确逻辑是属于**本地简单业务**还是**跨模块复杂业务**:
|
||||
- **方案 A(推荐,轻量化优先)**:直接在 `internal/apps/custom/logics.go` 下定义函数。该函数虽然在 `apps` 目录下,但同样应该**保持纯 Go 参数**(不直接操作 `*gin.Context`),仅供 Handler 层直接调用。
|
||||
- **方案 B(当满足“跨模块”、“复杂事务”、“多入口调用”时)**:在 `internal/service/` 下创建独立的业务 Service 方法,以实现逻辑复用和领域解耦。
|
||||
参考示例:[service_example.go](file:///Users/ryan/DEV/Go/Wavelet/.agent/skills/new-api/references/service_example.go)
|
||||
|
||||
### 步骤 3:在 `internal/apps/custom/` 下编写 HTTP Handler
|
||||
创建应用路由文件 `routers.go`,定义接口的请求和响应 DTO,编写 Handler 绑定参数并调用 Service,编写 Swagger 注释。
|
||||
参考示例:[handler_example.go](file:///Users/ryan/DEV/Go/Wavelet/.agent/skills/new-api/references/handler_example.go)
|
||||
|
||||
### 步骤 4:在 `internal/router/custom.go` 中注册路由
|
||||
创建路由挂载函数:
|
||||
```go
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/custom"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerCustomRoutes(apiV1Router *gin.RouterGroup) {
|
||||
customRouter := apiV1Router.Group("/custom")
|
||||
{
|
||||
customRouter.POST("/action", custom.DoActionHandler)
|
||||
}
|
||||
}
|
||||
```
|
||||
并在 [router.go](file:///Users/ryan/DEV/Go/Wavelet/internal/router/router.go) 中的 `/v1` 路由组末尾调用此函数。
|
||||
|
||||
---
|
||||
|
||||
## 质量验证与门禁 (Verification Quality Gates)
|
||||
|
||||
每当新增或修改 API 接口时,必须严格执行以下验证:
|
||||
|
||||
1. **生成授权许可**:
|
||||
新增 Go 文件后,运行自动添加许可证头部命令:
|
||||
```bash
|
||||
make license
|
||||
```
|
||||
|
||||
2. **生成 Swagger 文档**:
|
||||
在 Handler 编写完 `@Summary` 等 Swagger 注释后,必须生成更新:
|
||||
```bash
|
||||
make swagger
|
||||
```
|
||||
*注意:若 Swagger 生成失败,请仔细排查注释格式或数据类型引用是否规范。*
|
||||
|
||||
3. **静态代码检查与 Linting**:
|
||||
运行 `golangci-lint` 与前端 TypeScript 门禁,确保没有代码风格和类型安全隐患:
|
||||
```bash
|
||||
make code-check
|
||||
```
|
||||
|
||||
4. **编译与功能测试**:
|
||||
运行整包编译与自动化测试:
|
||||
```bash
|
||||
make build-test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关 Skills
|
||||
* [go-context](../go-context/SKILL.md):了解如何在 Service 层正确传递取消信号和追踪 Trace。
|
||||
* [go-error-handling](../go-error-handling/SKILL.md):了解如何优雅地将业务错误向上传递,并在 Handler 层决定响应状态码。
|
||||
* [database-migration](../database-migration/SKILL.md):当新增接口需要额外表结构或默认配置种子时配合使用。
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package references
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/service"
|
||||
"github.com/Rain-kl/Wavelet/internal/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// customRequest 客户端请求体 DTO
|
||||
type customRequest struct {
|
||||
Payload string `json:"payload" binding:"required,min=1,max=100"`
|
||||
}
|
||||
|
||||
// customResponse API 响应体 DTO
|
||||
type customResponse struct {
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
// HandleCustomBusiness 示例 API Handler
|
||||
// @Summary 示例定制业务接口
|
||||
// @Description 接收数据载荷,调用 Service 执行核心逻辑,并返回统一格式的 JSON 结果。
|
||||
// @Tags custom
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body customRequest true "业务请求参数"
|
||||
// @Success 200 {object} util.ResponseAny{data=customResponse} "操作成功"
|
||||
// @Router /api/v1/custom/business [post]
|
||||
func HandleCustomBusiness(c *gin.Context) {
|
||||
// 1. 参数绑定与校验
|
||||
var req customRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err("参数校验失败:载荷不能为空且在 1-100 字符内"))
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 模拟获取当前上下文与已登录用户(例如从 Session 中提取)
|
||||
// 通常结合 oauth.LoginRequired() 等中间件使用
|
||||
userID := int64(9527)
|
||||
|
||||
// 3. 实例化业务 Service 并调用核心逻辑
|
||||
// 注意传入 c.Request.Context() 以正确传递 OpenTelemetry Tracing 等上下文信息
|
||||
svc := service.NewCustomService()
|
||||
resText, err := svc.ProcessBusinessData(c.Request.Context(), userID, req.Payload)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 返回符合外层形状规范 { "error_msg": "", "data": ... } 的统一成功响应
|
||||
c.JSON(http.StatusOK, util.OK(customResponse{
|
||||
Result: resText,
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package references
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ProcessLocalBusiness 示例的模块内部闭环业务逻辑
|
||||
// 1. 虽然存放在 apps/custom/logics.go 下,但依然遵循纯 Go 规范,不强依赖 gin.Context,以便逻辑清晰和便于单元测试。
|
||||
// 2. 仅用于当前应用模块私有的简单业务,避免滥用全局的 internal/service 从而导致 Service 臃肿。
|
||||
func ProcessLocalBusiness(ctx context.Context, userID int64, param string) (string, error) {
|
||||
if param == "" {
|
||||
return "", errors.New("param cannot be empty")
|
||||
}
|
||||
|
||||
logger.Info(ctx, "processing local business inside apps/custom/logics",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.String("param", param),
|
||||
)
|
||||
|
||||
// 执行轻量级、无需跨模块/多入口复用的本地计算或模型操作
|
||||
result := fmt.Sprintf("Processed local logic for user %d: %s", userID, param)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package references
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// CustomService 示例业务 Service 结构体
|
||||
type CustomService struct {
|
||||
// 这里可以注入数据库连接、配置对象或者其他基础服务的客户端
|
||||
// 例如:db *gorm.DB
|
||||
}
|
||||
|
||||
// NewCustomService 创建 CustomService 实例的构造函数
|
||||
func NewCustomService() *CustomService {
|
||||
return &CustomService{}
|
||||
}
|
||||
|
||||
// ProcessBusinessData 演示核心业务处理逻辑的 Service 方法
|
||||
// 1. 首位参数必须是 context.Context,以传播链路追踪 (OTel) 和超时控制。
|
||||
// 2. 方法签名应该只包含纯 Go 的参数与返回值,禁止导入 Gin 或与 HTTP 相关的协议依赖。
|
||||
// 3. 将可能发生的核心异常通过 error 返回给上层,而不是在这一层转换成 HTTP 状态码。
|
||||
func (s *CustomService) ProcessBusinessData(ctx context.Context, userID int64, payload string) (string, error) {
|
||||
if payload == "" {
|
||||
return "", errors.New("payload cannot be empty")
|
||||
}
|
||||
|
||||
// 模拟执行业务逻辑...
|
||||
logger.Info(ctx, "processing custom business data in service",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.String("payload", payload),
|
||||
)
|
||||
|
||||
// 这里可以包含数据库读写、事务控制、或者远程 API 调用等复杂逻辑。
|
||||
result := fmt.Sprintf("Success processed data for user %d: %s", userID, payload)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -5,6 +5,7 @@ specialized workflows still live in `.agent/skills/`.
|
||||
|
||||
## Always Read The Matching Skill
|
||||
|
||||
- `new-api`: use when adding or changing custom business APIs, handlers, service layer logic, or registering customized endpoints.
|
||||
- `new-async-task`: use when adding or changing Asynq tasks, scheduled jobs,
|
||||
task metadata, task payload validation, task logs, task retry behavior, or
|
||||
Admin task APIs.
|
||||
|
||||
+32
-103
@@ -677,88 +677,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/db-manage/table-data": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"SessionCookie": []
|
||||
}
|
||||
],
|
||||
"description": "根据传入的数据表名称进行分页数据查询,返回表结构列名及动态行数据,需要管理员权限",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "获取数据表数据",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "表名称",
|
||||
"name": "table",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码,默认 1",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页大小,默认 10",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "获取成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/db_manage.TableDataResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "参数错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "未登录",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "无管理员权限",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "内部错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/db-manage/tables": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2574,6 +2492,38 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/custom/hello": {
|
||||
"get": {
|
||||
"description": "A sample business API for customization",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"custom"
|
||||
],
|
||||
"summary": "Sample Hello API",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/health": {
|
||||
"get": {
|
||||
"description": "检查服务是否正常运行,可用于负载均衡存活探测",
|
||||
@@ -4165,27 +4115,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"db_manage.TableDataResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"columns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logger.LogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+32
-103
@@ -670,88 +670,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/db-manage/table-data": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"SessionCookie": []
|
||||
}
|
||||
],
|
||||
"description": "根据传入的数据表名称进行分页数据查询,返回表结构列名及动态行数据,需要管理员权限",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "获取数据表数据",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "表名称",
|
||||
"name": "table",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码,默认 1",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页大小,默认 10",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "获取成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/db_manage.TableDataResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "参数错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "未登录",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "无管理员权限",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "内部错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/db-manage/tables": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2567,6 +2485,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/custom/hello": {
|
||||
"get": {
|
||||
"description": "A sample business API for customization",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"custom"
|
||||
],
|
||||
"summary": "Sample Hello API",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/util.ResponseAny"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/health": {
|
||||
"get": {
|
||||
"description": "检查服务是否正常运行,可用于负载均衡存活探测",
|
||||
@@ -4158,27 +4108,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"db_manage.TableDataResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"columns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logger.LogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+18
-64
@@ -114,20 +114,6 @@ definitions:
|
||||
description: '"select" 或 "exec"'
|
||||
type: string
|
||||
type: object
|
||||
db_manage.TableDataResponse:
|
||||
properties:
|
||||
columns:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
results:
|
||||
items:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: array
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
logger.LogEntry:
|
||||
properties:
|
||||
data:
|
||||
@@ -1365,56 +1351,6 @@ paths:
|
||||
summary: 执行 SQL 查询
|
||||
tags:
|
||||
- admin
|
||||
/api/v1/admin/db-manage/table-data:
|
||||
get:
|
||||
description: 根据传入的数据表名称进行分页数据查询,返回表结构列名及动态行数据,需要管理员权限
|
||||
parameters:
|
||||
- description: 表名称
|
||||
in: query
|
||||
name: table
|
||||
required: true
|
||||
type: string
|
||||
- description: 页码,默认 1
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 每页大小,默认 10
|
||||
in: query
|
||||
name: pageSize
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 获取成功
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/util.ResponseAny'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/db_manage.TableDataResponse'
|
||||
type: object
|
||||
"400":
|
||||
description: 参数错误
|
||||
schema:
|
||||
$ref: '#/definitions/util.ResponseAny'
|
||||
"401":
|
||||
description: 未登录
|
||||
schema:
|
||||
$ref: '#/definitions/util.ResponseAny'
|
||||
"403":
|
||||
description: 无管理员权限
|
||||
schema:
|
||||
$ref: '#/definitions/util.ResponseAny'
|
||||
"500":
|
||||
description: 内部错误
|
||||
schema:
|
||||
$ref: '#/definitions/util.ResponseAny'
|
||||
security:
|
||||
- SessionCookie: []
|
||||
summary: 获取数据表数据
|
||||
tags:
|
||||
- admin
|
||||
/api/v1/admin/db-manage/tables:
|
||||
get:
|
||||
description: 返回当前数据库的所有用户自定义表名称列表,需要管理员权限
|
||||
@@ -2509,6 +2445,24 @@ paths:
|
||||
summary: 获取公共配置
|
||||
tags:
|
||||
- config
|
||||
/api/v1/custom/hello:
|
||||
get:
|
||||
description: A sample business API for customization
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 成功
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/util.ResponseAny'
|
||||
- properties:
|
||||
data:
|
||||
type: string
|
||||
type: object
|
||||
summary: Sample Hello API
|
||||
tags:
|
||||
- custom
|
||||
/api/v1/health:
|
||||
get:
|
||||
description: 检查服务是否正常运行,可用于负载均衡存活探测
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package custom provides custom business handlers
|
||||
package custom
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Hello is a sample handler for custom business logic
|
||||
// @Summary Sample Hello API
|
||||
// @Description A sample business API for customization
|
||||
// @Tags custom
|
||||
// @Produce json
|
||||
// @Success 200 {object} util.ResponseAny{data=string} "成功"
|
||||
// @Router /api/v1/custom/hello [get]
|
||||
func Hello(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, util.OK("Hello from custom business module!"))
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/custom"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// registerCustomRoutes registers custom business routes to keep router.go clean and stable.
|
||||
func registerCustomRoutes(apiV1Router *gin.RouterGroup) {
|
||||
customRouter := apiV1Router.Group("/custom")
|
||||
{
|
||||
customRouter.GET("/hello", custom.Hello)
|
||||
}
|
||||
}
|
||||
@@ -280,6 +280,9 @@ func registerRoutes(r *gin.Engine) {
|
||||
adminRouter.PUT("/auth-sources/:id/toggle", admin_auth_source.ToggleAuthSource)
|
||||
adminRouter.DELETE("/auth-sources/:id", admin_auth_source.DeleteAuthSource)
|
||||
}
|
||||
|
||||
// Register custom business routes
|
||||
registerCustomRoutes(apiV1Router)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user