关于 REST 服务的实现已经有很多在线文章。同时,不同技术和库的组合更是多种多样。我在寻找一个使用 Go 实现、具有 Swagger UI 以便于手动测试、后端具有数据库且最小化样板代码的实现。这里是我使用的库:
- gorm 作为 ORM 库
- viper 用于配置管理
- gin 作为 Web 框架
- gin-swagger 用于从 Go 注释生成 OpenAPI 规范
包布局
我使用了 Ben Johnson 建议的包布局。这是从他的文章中提取的主要思想:
- 有一个面向领域的包(“描述数据和进程交互的逻辑高层语言”),不依赖于任何其他包。
- 在其他包中保持依赖关系,并复制包名称,以强制隔离外部依赖关系。例如,通过创建我们自己的“http”包,可以确保对“net/http”的引用仅驻留在我们的“http”中。
- 使用共享的 mock 子包和简单的手写 mock
遵循这些思想,我创建了以下包:
- domain: 用于服务接口和数据结构使用。
- gorm: 通过 ORM 抽象进行数据库交互。
- http: 用于处理 HTTP 流量。这也可以称为 gin,因为这是使用的框架。
- mock: 用于测试的 mock。
现在我们有了包布局,让我们来看看实现的一些细节。
面向领域
这里我们有一个简单的结构,非常适合演示。
我遵循了 gorm 约定 来命名 Task 中的字段。例如,ID 将成为主键。
gorm 包
这是与数据库交互的实现。由于使用了 gorm,这不会引入对数据库的直接依赖,这有助于在需要时更改数据库。但是,我在这个演示中使用 gorm 的动机更多是为了减少样板代码。我不想手动定义我的数据库模式,或手写 SQL。这样可以更快地启动并运行。 (尽管 gorm 也支持手写 SQL,这在构建更复杂的东西时可能会很方便。)
Gorm 还支持数据库迁移,这对于保持代码中数据结构与模式同步非常方便。
http 包
为了处理 HTTP 请求和实现路由,我们使用 Gin Web Framework。与 mux 相比,我发现 Gin 需要更少的样板代码。我喜欢你不需要使用 JSON 编码器 来返回 HTTP 响应中的 JSON。我还发现模型绑定很方便。这是一个示例,它展示了如何在任务创建处理程序中使用它。
路由在一个中心文件中单独定义,通过传递具有处理程序的接口来实现。
带 Swagger 的 Gin
Swag 将 Go 注释转换为 Swagger 文档 2.0。Open API Spec(又名 Swagger Spec)的最新版本是 3.0.3,但我没有找到支持 v3 的工具来生成规范。同时,我希望能够使用 Swagger UI 进行手动测试,这适用于 Open API v2 和 v3,因此它达到了预期效果。
规范生成也称为“代码优先方法”。API 的通用建议是先创建规范,然后从规范生成代码,以确保在实现完成后不会出现设计问题。但是,对于快速创建小型演示(如本文),代码优先方法可能更好。当你需要为现有服务创建规范时,也可能会有好处。
规范生成由 API 操作上的注释(在我们的情况下是处理程序实现)和数据结构上的标签驱动。
Swag 还支持最受欢迎的 Go Web 框架,如使用 gin-swagger 的 gin。使用此功能,我们可以添加一个处理程序来提供 Swagger UI。它可以与其他路由一起简单地定义。
单元测试和模拟
我使用了手写的简单 mock。
由于它实现了领域中的 TaskService 接口,因此它可以作为后端传递给 http.TaskService,以便测试处理程序。
一些摩擦:处理日期和时间
我唯一发现这些组件不容易使用的时候是处理日期和时间。Swag 不支持它,因此需要实现序列化和反序列化,并为 time.Time 定义一个包装器。
构建和运行
我们可以使用安装了 Go 二进制文件的容器映像构建一个容器映像
然后使用 docker-compose 启动包括数据库的本地测试环境
结论
在本文中,我们介绍了如何使用 Go 构建一个简单的 REST 服务。我们从包布局开始,然后实现了领域逻辑,使用 gorm 添加了 ORM 支持,并使用 gin 处理了 HTTP 流量和路由。我们还使用 swag 生成了 Open API 规范,并为测试构建了本地测试环境。
接下来,我们可以添加某种形式的身份验证和授权、日志记录,以及可能的部署脚本来部署到云提供商...
如果你对此主题有任何评论,请不要保留,发送评论:) 谢谢
译自:https://blog.devgenius.io/simple-rest-service-in-golang-with-openapi-spec-and-orm-a447b1086e21
评论(0)