以下创建一个 REST API 应用的最佳实践
库包:
- Gin for HTTP
- gorm for ORM
- viper for configuration
- zap for logging
- testify for testing
- go2hal for HAL
- problem for problem JSON
- validator for validation
- sqlmock for SQL mocking
完整代码示例
模型
使用ORM模型,在本例中,gorm使用该模型将结构转换为 SQL 语句。例如:
type Workspace struct { |
- ID用作主键,使用随机 UUID 而不是自增整数。
- name是模型的一个属性,它可以是任何名称下的任何有限数量的东西。
- 创建模型时的CreatedAt由 gorm 自动处理。
- UpdatedAt模型更新时,由 gorm 自动处理。
- DeletedAt这是 gorm 处理软删除的方式。它需要是 gorm.DeletedAt 的类型
存储库
存储库是一种设计模式,可以帮助我们进行CRUD操作。
我们先定义一个接口:
type Repository interface { |
然后他们使用 gorm 作为 ORM 的实现:
func (repository *WorkspaceRepository) List(after time.Time, limit int) (any, error) { |
路由
为了处理 HTTP 路由,我们需要创建一些称为控制器的函数,在这个例子中,使用了Gin。
func (server *Server) registerRoutes() { |
控制器
控制器负责处理 HTTP 调用并返回有用的信息,这些信息可以是带有来自 ORM 的对象的 JSON 或错误。让我们实现所有的 CRUD 操作:
func GetWorkspaceRepository(ctx *gin.Context) repository.Repository { |
HAL 链接
API 是永恒的。一旦将 API 集成到生产应用程序中,就很难进行可能破坏现有集成的重大更改
Web API 设计原则:使用 API 和微服务交付价值
在实践中,很难打破 API 契约,因为 API 使用者会生你的气。新版本的 API 不实用;没有人会转移到另一个 API。
考虑到这一点,正式名称为 JSON 超文本应用程序语言的HAL Links尝试以一种没有痛苦的方式解决 API 迁移。API 应该在self字段中返回资源的表示,而不是对资源使用硬编码的位置。
{ |
实现非常简单:
func (model *Workspace) ToHAL(selfHref string) (root hal.Resource) { |
问题
你可能已经注意到每个错误都会调用HandleError函数,这个函数负责通过返回application/problem+json将错误变成更有意义的东西。
func HandleError(err error, ctx *gin.Context) { |
例如,如果after参数不是RFC 3339的格式。它将返回一个错误
$ http localhost:8000/workspaces?after=0 |
注意Content-Type,它是HTTP APIs的问题细节的mimetype,正文中有一个详细的错误。