整洁架构示例
本示例展示了一个遵循整洁架构原则的 Go Fiber 应用。
描述
本项目提供了一个使用整洁架构构建 Web 应用的起点。它利用 Fiber 作为 Web 框架,MongoDB 作为数据库,并遵循整洁架构原则来分离关注点并提高可维护性。
要求
项目结构
api/
: 包含 HTTP 处理器、路由和展示器。pkg/
: 包含核心业务逻辑和实体。cmd/
: 包含主应用入口点。
设置
-
克隆仓库
git clone https://github.com/gofiber/recipes.git
cd recipes/clean-architecture -
在
.env
文件中设置环境变量DB_URI=mongodb://localhost:27017
DB_NAME=example_db -
安装依赖
go mod download
-
运行应用
go run cmd/main.go
API 现在应该正在 http://localhost:3000
上运行。
API 端点
API 中提供了以下端点
- GET /books: 列出所有书籍。
- POST /books: 添加一本新书。
- PUT /books: 更新一本现有书籍。
- DELETE /books: 删除一本书籍。
使用示例
-
添加一本新书
curl -X POST http://localhost:3000/books -d '{"title":"Book Title", "author":"Author Name"}' -H "Content-Type: application/json"
-
列出所有书籍
curl http://localhost:3000/books
-
更新一本书籍
curl -X PUT http://localhost:3000/books -d '{"id":"<book_id>", "title":"Updated Title", "author":"Updated Author"}' -H "Content-Type: application/json"
-
删除一本书籍
curl -X DELETE http://localhost:3000/books -d '{"id":"<book_id>"}' -H "Content-Type: application/json"
将 <book_id>
替换为书籍的实际 ID。
整洁架构原则
整洁架构是一种软件设计哲学,强调关注点分离,使代码库更易于维护、测试和扩展。在本示例中,Go Fiber 应用通过将代码组织成不同的层,每层承担自己的责任,从而遵循了整洁架构原则。
整洁架构中的层
- 实体 (核心业务逻辑)
- 位于
pkg/entities
目录。 - 包含核心业务逻辑和领域模型,它们独立于任何外部框架或技术。
- 用例 (应用逻辑)
- 位于
pkg/book
目录。 - 包含特定于应用的业务规则和用例。该层协调数据在实体之间的流动。
- 接口适配器 (适配器和展示器)
- 位于
api
目录。 - 包含 HTTP 处理器、路由和展示器。该层负责将用例中的数据转换为适合 Web 框架(此处为 Fiber)的格式。
- 框架和驱动 (外部接口)
- 位于
cmd
目录。 - 包含主应用入口点以及任何外部依赖,例如 Web 服务器设置。
示例分解
- 实体:
entities.Book
结构体代表书籍的核心业务模型。 - 用例:
book.Service
接口定义了与书籍交互的方法,例如InsertBook
,UpdateBook
,RemoveBook
, 和FetchBooks
。 - 接口适配器:
handlers
包包含与book.Service
交互的 HTTP 处理器,用于处理 HTTP 请求和响应。 - 框架和驱动:
cmd/main.go
文件初始化 Fiber 应用并使用routes.BookRouter
函数设置路由。
代码示例
entities/book.go
package entities
import "go.mongodb.org/mongo-driver/bson/primitive"
type Book struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Title string `json:"title"`
Author string `json:"author"`
}
pkg/book/service.go
package book
import "clean-architecture/pkg/entities"
type Service interface {
InsertBook(book *entities.Book) (*entities.Book, error)
UpdateBook(book *entities.Book) (*entities.Book, error)
RemoveBook(id primitive.ObjectID) error
FetchBooks() ([]*entities.Book, error)
}
api/handlers/book_handler.go
package handlers
import (
"clean-architecture/pkg/book"
"clean-architecture/pkg/entities"
"clean-architecture/api/presenter"
"github.com/gofiber/fiber/v2"
"net/http"
"errors"
)
func AddBook(service book.Service) fiber.Handler {
return func(c *fiber.Ctx) error {
var requestBody entities.Book
err := c.BodyParser(&requestBody)
if err != nil {
c.Status(http.StatusBadRequest)
return c.JSON(presenter.BookErrorResponse(err))
}
if requestBody.Author == "" || requestBody.Title == "" {
c.Status(http.StatusInternalServerError)
return c.JSON(presenter.BookErrorResponse(errors.New("Please specify title and author")))
}
result, err := service.InsertBook(&requestBody)
if err != nil {
c.Status(http.StatusInternalServerError)
return c.JSON(presenter.BookErrorResponse(err))
}
return c.JSON(presenter.BookSuccessResponse(result))
}
}
cmd/main.go
package main
import (
"clean-architecture/api/routes"
"clean-architecture/pkg/book"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
bookService := book.NewService() // Assume NewService is a constructor for the book service
routes.BookRouter(app, bookService)
app.Listen(":3000")
}
通过遵循整洁架构原则,本示例确保每一层都是独立的,可以修改或替换而不会影响其他层,从而实现更易于维护和扩展的应用。
结论
本示例提供了一个遵循整洁架构原则的 Go Fiber 应用的基本设置。它可以进一步扩展和定制,以满足更复杂应用的需求。