跳到主要内容

宣布 "entoas" - 一个自动从 Ent Schemas 生成 OpenAPI 规范文档的扩展

· 阅读需 8 分钟

OpenAPI 规范(OAS,之前称为 Swagger 规范)是一份技术规范,用于为 REST API 定义一个标准的、与语言无关的接口描述。这使人类和自动化工具能够在没有实际源代码或额外文档的情况下理解所描述的服务。结合 Swagger Tooling,您只需传入 OAS 文档,即可为 20 多种语言生成服务器端和客户端模板代码。

在先前的 博客文章 中,我们向您介绍了 Ent 扩展 elk 的一个新功能:一个完全符合规范的 OpenAPI 规范 文档生成器。

今天,我们非常高兴地宣布,规范生成器已成为 Ent 项目的官方扩展,并已迁移到 ent/contrib 仓库。此外,我们聆听了社区的反馈,并对生成器进行了修改,希望您会喜欢。

入门

要使用 entoas 扩展,请按 这里 的说明使用 entc(ent 代码生成器)包。首先将扩展安装到您的 Go 模块中:

go get entgo.io/contrib/entoas

现在按照下面两个步骤启用并配置 Ent 与 entoas 扩展:

1. 创建一个名为 ent/entc.go 的新 Go 文件,并粘贴以下内容:

// +build ignore

package main

import (
"log"

"entgo.io/contrib/entoas"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)

func main() {
ex, err := entoas.NewExtension()
if err != nil {
log.Fatalf("创建 entoas 扩展时出错: %v", err)
}
err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex))
if err != nil {
log.Fatalf("运行 ent 代码生成时出错: %v", err)
}
}

2. 编辑 ent/generate.go 文件以执行 ent/entc.go

package ent

//go:generate go run -mod=mod entc.go

完成上述步骤后,您已准备好从 Schema 生成 OAS 文档!如果您是 Ent 新手,并想了解其如何连接到不同类型的数据库、运行迁移或处理实体,请前往 设置教程

生成 OAS 文档

创建 Ent Schema 图是我们的首个步骤。这里给出一个简短示例 Schema 用于演示:

ent/schema/schema.go
// Fridge 代表 Fridge 实体的 schema 定义。
package schema

import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)

// Fridge 代表 Fridge 实体的 schema 定义。
type Fridge struct {
ent.Schema
}

// Fridge 的字段。
func (Fridge) Fields() []ent.Field {
return []ent.Field{
field.String("title"),
}
}

// Fridge 的边。
func (Fridge) Edges() []ent.Edge {
return []ent.Edge{
edge.To("compartments", Compartment.Type),
}
}

// Compartment 代表 Compartment 实体的 schema 定义。
type Compartment struct {
ent.Schema
}

// Compartment 的字段。
func (Compartment) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}

// Compartment 的边。
func (Compartment) Edges() []ent.Edge {
return []ent.Edge{
edge.From("fridge", Fridge.Type).
Ref("compartments").
Unique(),
edge.To("contents", Item.Type),
}
}

// Item 代表 Item 实体的 schema 定义。
type Item struct {
ent.Schema
}

// Item 的字段。
func (Item) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}

// Item 的边。
func (Item) Edges() []ent.Edge {
return []ent.Edge{
edge.From("compartment", Compartment.Type).
Ref("contents").
Unique(),
}
}

上述代码是 Ent 描述 Schema 图的方式。在本例中,我们创建了三个实体:Fridge、Compartment 和 Item,并为图添加了一些边:Fridge 可以拥有多个 Compartment,Compartment 可以包含多个 Item。

现在运行代码生成器:

go generate ./...

除 Ent 通常生成的文件之外,还会创建一个名为 ent/openapi.json 的文件。以下是该文件的一览:

ent/openapi.json
{
"info": {
"title": "Ent 图谱 API",
"description": "这是基于 Ent schema 定义自动生成的 API 描述",
"termsOfService": "",
"contact": {},
"license": {
"name": ""
},
"version": "0.0.0"
},
"paths": {
"/compartments": {
"get": {
[...]

如果您想尝试一下,可以将其内容复制并粘贴到 Swagger Editor。它应该会如下面所示:

Swagger 编辑器

Swagger 编辑器

基本配置

我们的 API 描述尚未准确反映它的功能,但 entoas 让您可以更改!打开 ent/entc.go,传入更新后的标题和描述:

ent/entc.go
//go:build ignore
// +build ignore

package main

import (
"log"

"entgo.io/contrib/entoas"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)

func main() {
ex, err := entoas.NewExtension(
entoas.SpecTitle("冰箱 CMS"),
entoas.SpecDescription("API 用于管理冰箱及其冷藏内容。**ICY!**"),
entoas.SpecVersion("0.0.1"),
)
if err != nil {
log.Fatalf("创建 entoas 扩展时出错: %v", err)
}
err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex))
if err != nil {
log.Fatalf("运行 ent 代码生成时出错: %v", err)
}
}

重新运行代码生成器将生成更新后的 OAS 文档:

ent/openapi.json
{
"info": {
"title": "冰箱 CMS",
"description": "API 用于管理冰箱及其冷藏内容。**ICY!**",
"termsOfService": "",
"contact": {},
"license": {
"name": ""
},
"version": "0.0.1"
},
"paths": {
"/compartments": {
"get": {
[...]

操作配置

有时您不想为每个节点的每个操作都生成端点。幸运的是,entoas 让我们配置需要生成哪些端点,哪些忽略。entoas 的默认策略是公开所有路由。您可以将此行为改为仅公开显式请求的路由,或仅通过 entoas.Annotation 排除特定操作。策略也可用于开启/关闭子资源操作的生成:

ent/schema/fridge.go
// Fridge 的边。
func (Fridge) Edges() []ent.Edge {
return []ent.Edge{
edge.To("compartments", Compartment.Type).
// 不生成 POST /fridges/{id}/compartments 端点
Annotations(
entoas.CreateOperation(
entoas.OperationPolicy(entoas.PolicyExclude),
),
),
}
}

// Fridge 的注解。
func (Fridge) Annotations() []schema.Annotation {
return []schema.Annotation{
// 不生成 DELETE /fridges/{id} 端点
entoas.DeleteOperation(entoas.OperationPolicy(entoas.PolicyExclude)),
}
}

完成!操作已被移除。

如需了解 entoas 的策略工作原理和可做的事情,请查看 godoc

简单模型

默认情况下,entoas 为每个端点生成一个响应 schema。了解命名策略,请查看 godoc

每端点一个 Schema

每端点一个 Schema

许多用户请求将此行为改为直接将 Ent schema 映射到 OAS 文档。现在,您可以这样配置 entoas

ex, err := entoas.NewExtension(
entoas.SpecTitle("冰箱 CMS"),
entoas.SpecDescription("API 用于管理冰箱及其冷藏内容。**ICY!**"),
entoas.SpecVersion("0.0.1"),
entoas.SimpleModels(),
)
简单 Schema

简单 Schema

小结

在本文中我们宣布了 entoas,即前 elk OpenAPI 规范生成器与 Ent 的官方集成。此功能将 Ent 的代码生成能力与 OpenAPI/Swagger 丰富的工具生态系统相结合。

有问题吗?需要帮助入门吗?请随时加入我们的 Discord 服务器Slack 频道

更多 Ent 新闻与更新:
  • 订阅我们的新闻通讯
  • 在 Twitter 上关注我们
  • 加入 Gophers Slack 上的 #ent
  • 加入 Ent Discord 服务器