使用 Go 中的六边形架构构建 RESTful API
前往 POS
一段时间以来,我一直在学习如何使用不同的框架和语言构建 Web 应用程序,例如 采用 MVC 架构的 Laravel和遵循“Hapi.js 方式”的 Node.js。 当我尝试使用 Go 创建一个新的作品集项目时,我发现自己开始思考理想的项目结构。我想要一个不仅符合 标准 Go 项目布局 的架构 ,还要使代码易于编写和理解的结构。就在那时,我偶然发现了六边形架构的概念,正如 Netflix 的工程博客 中所展示的那样。以最少的代码更改无缝切换基础架构的想法让我着迷,于是我决定在我的新项目中实现它。
现在,剩下的问题是: “我应该构建什么?” 幸运的是,当我随意浏览 YouTube 视频时,我偶然发现了 Asdita Prasetya 制作的这个隐藏的精品视频,名为 “Ide Project untuk Upgrade Portfolio Backend Engineer” 。他建议开发一个 RESTful 的销售点 API 服务。我觉得这是一个将我新学到的架构知识付诸实践的完美项目。于是,我准备好咖啡和键盘,开始了这段激动人心的学习之旅!
六边形架构
创建无需 UI 或数据库即可运行的应用程序,以便您可以针对应用程序运行自动回归测试,在数据库不可用时继续工作,并且无需任何用户参与即可将应用程序链接在一起。
六边形架构 (也称为端口和适配器架构)是构建解耦软件系统的几种方法之一。它由 Alistair Cockburn 推广,他被誉为软件开发敏捷运动的创始人之一。这种组织软件的方式非常适合开发易于操作且易于修改的应用程序。
六边形架构的核心思想是将应用程序的核心业务逻辑与外部内容(例如数据库、用户界面和其他外部服务)分离。它提倡一种简洁、模块化的结构,使应用程序的测试、维护和扩展更加容易。
核
核心是应用程序的核心所在。它包含应用程序的基本业务逻辑和规则。它负责处理订单、管理用户账户以及执行应用程序的所有任务。核心应该独立于任何外部技术或框架,从而实现高度的可移植性和可重用性。
六边形架构中还有另外两个重要概念:“端口”和“适配器”。这两个概念规定了“核心”如何与外部组件交互。
端口
将端口视为契约或接口。它们定义了应用程序如何与外部系统或服务通信。例如,端口可以指定连接数据库、与其他 Web 服务交互或处理用户界面的规则。端口属于核心,因为核心定义了实现业务逻辑目标所需的操作。
适配器
适配器负责实现端口定义的契约或接口。适配器负责确保应用程序能够与数据库、Web 服务或其他对象进行交互。它们处理技术细节。
驾驶员演员
驱动 Actor 是与核心通信的发起者。它们会联系核心来请求特定的服务。驱动 Actor 的例子可以是 HTTP 请求或命令行界面 (CLI)。
驱动 Actor
驱动 Actor 是由核心触发的 Actor。如果核心需要外部服务,它会向适配器发送请求,指示其执行特定操作。例如,如果核心需要将数据存储到 Postgres 数据库中,它会触发与 Postgres 客户端的通信以执行 INSERT 查询。在这种情况下,核心会发起通信。
执行
要求
Asdita 非常贴心地提供了 数据库架构设计 和 Postman API 文档 。所以我只需按照六边形架构原则构建我的应用程序,然后开始编写代码即可。
技术栈
为了构建 RESTful 销售点服务 API,我考虑并选择了多种能够无缝协作的技术组合。对于处理 HTTP 请求和响应,使用 Gin HTTP Web 框架 是合理的,因为我认为它在 Go 社区中功能完善且广受欢迎。为了确保数据完整性和持久性,我使用 PostgreSQL 数据库,并以 pgx作为数据库驱动程序。之所以选择 PostgreSQL,是因为它是生产环境中最流行的关系数据库,并且能够高效地与 Go 集成。我还使用 go-redis 客户端库中的 Redis 实现了缓存功能 ,该库提供了强大的内存数据存储功能。
数据库架构
users
:存储用户信息,包括姓名、电子邮件、密码、角色(管理员或收银员)以及创建和更新的时间戳。
payments
:存储各种付款方式。它跟踪付款类型、名称、标识以及创建和更新的时间戳。
categories
:存储产品类别,跟踪类别名称以及创建和更新的时间戳。
products
:存储基本产品数据,包括类别 ID、SKU、名称、库存水平、价格、图像以及创建和更新的时间戳。
orders
:存储订单详细信息,例如用户 ID、付款 ID、客户姓名、总价、付款、退货、收据代码以及创建和更新的时间戳。
order_products
:存储每笔订单中包含的产品记录。它记录订单和产品 ID、数量、总价以及创建和更新的时间戳。
应用程序架构
该应用程序遵循六边形架构,以六边形表示。 core
其中心 domain
包含 service
业务逻辑。
核心左侧有一个 driver port
,是驱动适配器的入口,右侧有2个 driven ports
,是核心与驱动适配器交互的门。
围绕核心, adapters
连接核心与外部世界。左侧 HTTP adapter
负责处理传入的 HTTP 请求。右侧有两个适配器: DB adapter
一个连接到 PostgreSQL,另一个 Cache adapter
与 Redis 配合使用。
和 位于应用程序外部。左侧的 Nginx 充当 HTTP 服务器, driver actors
右侧 的 PostgreSQL 和 Redis 代表 响应核心请求。 driven actors
driver actor
driven actors
项目结构
.
├── bin
├── cmd
│ └── http
├── docs
└── internal
├── adapter
│ ├── cache
│ │ └── redis
│ ├── handler
│ │ └── http
│ ├── repository
│ │ └── postgres
│ │ └── migrations
│ └── token
│ └── paseto
└── core
├── domain
├── port
├── service
└── util
21 directories
Enter fullscreen mode
Exit fullscreen mode
bin
:用于存储已编译的可执行二进制文件的目录。
docs
:用于存储项目文档的目录,例如 swagger 静态文件。
cmd
:应用程序主入口点或命令的目录。 http
子目录包含主 HTTP 服务器入口点。
internal
:包含不应暴露给外部包的应用程序代码的目录。
core
:包含应用程序的核心业务逻辑的目录。其中包含 4 个子目录。
domain
:包含代表核心业务概念的域模型/实体的目录。
port
:包含适配器必须遵循的已定义接口或契约的目录。
service
:包含应用程序的业务逻辑或服务的目录。
util
:包含在包中重复使用的实用函数的目录 service
。
adapters
:用于包含与应用程序核心交互的外部服务的目录。本应用程序使用了 4 个外部服务。
handler/http
:包含 HTTP 请求和响应处理程序的目录。
repository/postgres
:包含 PostgreSQL 数据库适配器的目录。
cache/redis
:包含 Redis 缓存适配器的目录。
token/paseto
:包含使用 Paseto 的令牌生成和验证适配器的目录。
开发工具
我在开发过程中使用过一些工具来简化流程。这些工具以不同的方式提供帮助。
Podman
Podman 是一个类似于 Docker 的容器化工具,用于管理应用程序的容器。它简化了容器的构建、运行和维护等任务。它是创建隔离的开发环境(例如 PostgreSQL 和 Redis 实例)的理想选择。
DBDocs
DBDocs 是一个数据库文档生成器。它自动生成数据库模式的文档,帮助理解和管理数据库结构,尤其是在使用 PostgreSQL 等关系数据库时。
任务文件
Taskfile 是一款用于简化重复性开发任务的工具。它有助于自动化构建、测试和部署应用程序等活动。与 Makefile 不同,Taskfile 使用 YAML 进行配置,使其更具可读性和用户友好性。
Golang-migrate
Golang-migrate 是一款专为 Go 应用程序设计的数据库迁移工具。它可以帮助管理和应用随着应用程序的增长而对数据库模式进行的更改,确保代码和数据库结构保持同步。
空气
Air 是一款 Go 应用的自动重启工具,它可以监测代码变化并自动重启应用,从而提高开发效率。
斯瓦戈
Swaggo 是一款为 Go API 创建 Swagger 文档的工具。它使 API 端点的文档编写更加简单,从而帮助开发人员理解和使用 API。
Golangci-lint
Golangci-lint 是一款用于检查 Go 代码质量、查找问题、错误和代码风格问题的工具。它有助于保持代码整洁且易于维护。
Github Actions
GitHub Actions 是一个与 GitHub 存储库链接的平台,用于自动执行构建、测试和部署应用程序等任务。它简化了开发并确保了代码质量。
部署
我创建了一个 GitHub Action 工作流来自动化应用程序的容器化过程,并将其上传到 GitHub 容器注册表 。然后,我手动将其部署到我的个人 VPS 上,并使用 Nginx 作为反向代理。我可能会考虑再写一篇博客文章来解释我的 VPS 设置。
您可以通过以下 URL 浏览该应用程序的 Swagger 文档: https://gopos.bagashiz.me/docs/index.html
源代码
我不想让这篇文章太长。所以如果你感兴趣,请在我的 GitHub 仓库 中查看该项目的完整源代码。你可以访问和探索代码库,查看应用程序的结构,甚至为其开发做出贡献。
用 Go 编写的简单 RESTful 销售点 (POS) 服务 API,使用了 Gin Web 框架、PostgreSQL 数据库和 Redis 缓存。本文提供了用 Go 实现六边形架构的概念验证。
改进
我承认这个项目还有一些地方有待改进:
截至目前,单元测试尚未实施。
该项目目前使用 slog
标准库中的包进行日志记录。但切换到更高级的记录器(例如), zap
可以提供更多灵活性和功能。
与其直接使用来访问环境变量 os.Getenv()
,不如集成一个配置处理程序,这样 viper
可能会使其更易于维护。
参考
文章来源:https://dev.to/bagashiz/building-restful-api-with-hexagonal-architecture-in-go-1mij