扩展
引言
Ent 的 扩展 API
有助于创建代码生成扩展,这些扩展将代码生成钩子、
模板 和注解捆绑在一起,以创建可重用的组件,
为 Ent 核心添加新的丰富功能。例如,Ent 的 entgql 插件
暴露了一个 Extension,可以从 Ent 模式自动生成 GraphQL 服务器。
定义新扩展
所有扩展都必须实现 Extension 接口:
type Extension interface {
// Hooks 包含一系列在代码生成前后应用于图的可选钩子
Hooks() []gen.Hook
// Annotations 向 gen.Config 对象注入全局注解,
// 这些注解可以在所有模板中全局访问。与模式注解不同,
// 不需要强制可序列化为 JSON 原始值。
//
// {{- with $.Config.Annotations.GQL }}
// {{/* 注解用法在此处 */}}
// {{- end }}
//
Annotations() []Annotation
// Templates 指定要执行或覆盖默认模板的
// 替代模板列表。
Templates() []*gen.Template
// Options 指定在执行代码生成之前要在 gen.Config 上
// 评估的 entc.Options 列表。
Options() []Option
}
为了简化新扩展的开发,开发者可以嵌入 entc.DefaultExtension 来创建扩展,而无需实现所有方法:
package hello
// GreetExtension 实现 entc.Extension。
type GreetExtension struct {
entc.DefaultExtension
}
添加模板
Ent 支持添加在代码生成期间渲染的外部模板。要在扩展上捆绑此类外部模板,请实现 Templates
方法:
{{/* 告诉 Intellij/GoLand 启用基于 *gen.Graph 类型的自动补全。 */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "greet" }}
{{/* 为生成的文件添加基础头部 */}}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
{{/* 循环所有节点并添加 Greet 方法 */}}
{{ range $n := $.Nodes }}
{{ $receiver := $n.Receiver }}
func ({{ $receiver }} *{{ $n.Name }}) Greet() string {
return "Hello, {{ $n.Name }}"
}
{{ end }}
{{ end }}
func (*GreetExtension) Templates() []*gen.Template {
return []*gen.Template{
gen.MustParse(gen.NewTemplate("greet").ParseFiles("templates/greet.tmpl")),
}
}
添加全局注解
注解是一种方便的方式,为扩展的用户提供 API 来修改代码生成的行为。要向我们的扩展添加注解,
请实现 Annotations 方法。假设在我们的 GreetExtension 中,我们想
为用户提供配置生成代码中问候词语的能力:
// GreetingWord 实现 entc.Annotation。
type GreetingWord string
// 注解的名称。由代码生成模板使用。
func (GreetingWord) Name() string {
return "GreetingWord"
}
然后将其添加到 GreetExtension 结构体中:
type GreetExtension struct {
entc.DefaultExtension
word GreetingWord
}
接下来,实现 Annotations 方法:
func (s *GreetExtension) Annotations() []entc.Annotation {
return []entc.Annotation{
s.word,
}
}
现在,从您的模板中可以访问 GreetingWord 注解:
func ({{ $receiver }} *{{ $n.Name }}) Greet() string {
return "{{ $.Annotations.GreetingWord }}, {{ $n.Name }}"
}
添加钩子
entc 包提供了一个选项,用于向代码生成阶段添加一系列钩子
(中间件)。此选项非常适合为模式添加自定义验证器,或使用图模式生成其他资产。要将
代码生成钩子与您的扩展捆绑,请实现 Hooks 方法:
func (s *GreetExtension) Hooks() []gen.Hook {
return []gen.Hook{
DisallowTypeName("Shalom"),
}
}
// DisallowTypeName 确保图中没有具有给定名称的 ent.Schema。
func DisallowTypeName(name string) gen.Hook {
return func(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
for _, node := range g.Nodes {
if node.Name == name {
return fmt.Errorf("entc: validation failed, type named %q not allowed", name)
}
}
return next.Generate(g)
})
}
}
在代码生成中使用扩展
要在我们的代码生成配置中使用扩展,请使用 entc.Extensions,这是一个辅助
方法,返回应用我们选择的扩展的 entc.Option:
//+build ignore
package main
import (
"fmt"
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)
func main() {
err := entc.Generate("./schema",
&gen.Config{},
entc.Extensions(&GreetExtension{
word: GreetingWord("Shalom"),
}),
)
if err != nil {
log.Fatal("running ent codegen:", err)
}
}
社区扩展
entoas
entoas是一个源自elk的扩展,已移植为自己的扩展,现在是官方 生成器,用于生成固执己见的 OpenAPI 规范文档。您可以使用它快速开发和记录 RESTful HTTP 服务器。很快将发布一个新的扩展,提供一个使用ent集成entoas提供的文档的生成实现。entrest
entrest是entoas(+ogent)和elk(在其停产之前)的替代方案。entrest 从您的 Ent 模式生成符合规范、 高效且功能完整的 OpenAPI 规范,以及功能性的 RESTful API 服务器实现。其亮点功能包括:可切换的分页、 高级过滤/查询功能、排序(甚至通过关系)、预先加载边,以及更多功能。entgql 此扩展帮助用户从 Ent 模式构建 GraphQL 服务器。
entgql与 gqlgen 集成,这是一个流行的、模式优先的 Go 库,用于构建 GraphQL 服务器。 该扩展包括生成类型安全的 GraphQL 过滤器,使用户能够轻松地将 GraphQL 查询映射到 Ent 查询。 遵循本教程开始使用。entproto
entproto从 Ent 模式生成 Protobuf 消息定义和 gRPC 服务定义。该项目还包括protoc-gen-entgrpc,一个protoc(Protobuf 编译器)插件,用于生成由 Entproto 生成的 gRPC 服务定义的 工作实现。通过这种方式,我们可以轻松创建一个 gRPC 服务器,无需编写任何代码(除了定义 Ent 模式外)即可服务于 我们的服务请求! 要了解如何使用和设置entproto,请阅读本教程。更多背景信息, 您可以阅读这篇博文, 或这篇博文讨论更多entproto功能。elk (已停产)
elk是一个从 Ent 模式生成 RESTful API 端点的扩展。该扩展从 Ent 模式生成 HTTP CRUD 处理程序,以及一个 OpenAPI JSON 文件。通过使用它,您可以轻松为您的应用程序构建 RESTful HTTP 服务器。 请注意,elk已停产,转而支持entoas。一个实现生成器正在开发中。 阅读这篇博文了解如何 使用elk,以及这篇博文了解如何生成 OpenAPI 规范。entviz (已停产)
entviz是一个从 Ent 模式生成可视化图表的扩展。这些图表在 Web 浏览器中可视化模式, 并随着我们继续编码而保持更新。entviz可以配置为每次我们重新生成模式时自动更新图表, 从而便于查看所做的更改。 在这篇博文中学习如何 在您的项目中集成entviz。此扩展已于 2023-09-16 由维护者存档。