fix: support recursive response DTOs and release v0.28.2

This commit is contained in:
2026-09-30 12:56:34 +08:00
parent f2c5957c15
commit 0c5b571b31
24 changed files with 978 additions and 91 deletions

View File

@@ -0,0 +1,32 @@
# 递归响应类型
通用节点、树集合和相互引用对象的响应示例。没有数据库、权限或业务服务依赖。
在 go-omni 仓库根目录执行(新建独立临时目录):
```sh
go install git.yuntuo.hk/k2safe/go-omni/cmd/go-omni@v0.28.2-preview
example_dir="$(mktemp -d)/recursive"
go-omni api generate --api examples/recursiveResponse/service.api --dir "$example_dir" --module example.com/recursive
# 以下文件仅是本次新生成示例的占位实现,替换为示例自身维护的逻辑。
for name in tree forest optional raw pair; do
printf 'package trees\n' > "$example_dir/internal/logic/trees/$name.go"
done
cp examples/recursiveResponse/operations.go.txt "$example_dir/internal/logic/trees/operations.go"
cd "$example_dir"
go mod tidy
go-omni api generate --check
go test ./...
go run .
```
按启动日志显示的监听地址访问 `/tree`、`/forest`、`/optional`、`/raw`、`/pair`。前三层节点通过 `[]types.Node` 编译和返回;`/optional` 返回 null,`/raw` 直接返回节点,`/pair` 返回相互引用类型的有限实例。`docs/openapi.json` 中的 `DTO_Node` 通过 `$ref` 引用自身,`DTO_Branch`、`DTO_Leaf` 互相引用。
嵌套集合遵循普通 Go JSON 规则,示例将叶节点的 Children 初始化为空切片,使其输出 `[]`;框架不会递归改写项目返回数据。业务数据不能包含实际指针环。
框架开发时可在首次生成命令后加 `--framework-dir .` 使用本地代码。回归同时覆盖本地与已发布远程 CLI、真实 HTTP 响应、生成幂等与只读漂移检查:
```sh
# 回到 go-omni 仓库根目录执行
GO_OMNI_SCAFFOLD_INTEGRATION=1 go test -race -count=1 ./cmd/go-omni/apigen -run Recursive
```

View File

@@ -0,0 +1,22 @@
package trees
import (
"context"
"example.com/recursive/internal/types"
)
func sample() types.Node {
return types.Node{Name: "root", Children: []types.Node{
{Name: "child", Children: []types.Node{
{Name: "leaf", Children: []types.Node{}},
}},
}, Lookup: map[string]types.Node{"entry": {Name: "lookup", Children: []types.Node{}}}}
}
func (s *Logic) Tree(context.Context) (*types.Node, error) { node := sample(); return &node, nil }
func (s *Logic) Forest(context.Context) ([]types.Node, error) { return []types.Node{sample()}, nil }
func (s *Logic) Optional(context.Context) (*types.Node, error) { return nil, nil }
func (s *Logic) Raw(context.Context) (*types.Node, error) { node := sample(); return &node, nil }
func (s *Logic) Pair(context.Context) (*types.Branch, error) {
return &types.Branch{Leaf: &types.Leaf{}}, nil
}

View File

@@ -0,0 +1,33 @@
type Node {
Name string `json:"name" binding:"min=1"`
Children []Node `json:"children" binding:"max=100"`
Next *Node `json:"next,omitempty"`
Lookup map[string]Node `json:"lookup,omitempty"`
}
type Branch {
Leaf *Leaf `json:"leaf"`
}
type Leaf {
Branch *Branch `json:"branch"`
}
@server (group: trees)
service recursive-example {
@handler tree
get /tree returns (Node)
@handler forest
get /forest returns ([]Node)
@handler optional
get /optional returns (*Node)
@handler raw
@response raw
get /raw returns (Node)
@handler pair
get /pair returns (Branch)
}