图书管理 API 服务
模拟真实世界的一个书店的图书管理后端服务。这个服务为平台前端以及其他客户端,提供针对图书的 CRUD(创建、检索、更新与删除)的基于 HTTP 协议的 API。API 采用典型的 RESTful 风格设计,这个服务提供的 API 集合如下:
客户端和服务端中请求与响应的数据,采用放在 HTTP 协议包体(Body)中的 Json 格式数据来承载
项目码云链接
项目测试
将项目先运行起来
使用postman发送post、get请求
- 请求头都设置为json
- post
# post请求的url
localhost:8080/book
#json
{
"id": "978-7-111-55842-2",
"name": "The Go Programming Language",
"authors": ["Alan A.A.Donovan", "Brian W. Kergnighan"],
"press": "Pearson Education"
}
- get
# get请求的url
localhost:8080/book/978-7-111-55842-2
发送get请求后,得到响应数据,如下:
项目结构布局
├── cmd/
│ └── bookstore/ // 放置bookstore main包源码
│ └── main.go
├── go.mod // module bookstore的go.mod
├── go.sum
├── internal/ // 存放项目内部包的目录
│ └── store/
│ └── memstore.go
├── server/ // HTTP服务器模块
│ ├── middleware/
│ │ └── middleware.go
│ └── server.go
└── store/ // 图书数据存储模块
├── factory/
│ └── factory.go
└── store.go
项目代码分析
- main
通过监视系统信号实现了 http 服务实例的优雅退出
优雅退出,指的就是程序有机会等待其他的事情处理完再退出。比如尚未完成的事务处理、清理资源(比如关闭文件描述符、关闭 socket)、保存必要中间状态、内存数据持久化落盘等等。
- 图书数据存储模块(store)
采用的存储方式在内存中创建一个 map,以图书 id 作为 key,来保存图书信息,但如果要考虑上生产环境,数据要进行持久化,那么最实际的方式就是通过 Nosql 数据库甚至是关系型数据库,实现对图书数据的存储与管理。
store/factory.go中采用了工厂模式来实现满足 Store 接口实例的创建。factory 包采用了一个 map 类型数据,对工厂可以“生产”的、满足 Store 接口的实例类型进行管理。factory 包还提供了 Register 函数,让各个实现 Store 接口的类型可以把自己“注册”到工厂中来。一旦注册成功,factory 包就可以“生产”出这种满足 Store 接口的类型实例。而依赖 Store 接口的使用方,只需要调用 factory 包的 New 函数,再传入期望使用的图书存储实现的名称,就可以得到对应的类型实例了。 - HTTP 服务模块(server)
对外提供 HTTP API 服务,处理来自客户端的各种请求,并通过 Store 接口实例执行针对图书数据的相关操作。
由于这个服务请求 URI 的模式字符串比较复杂,标准库 http 包内置的 URI 路径模式匹配器(ServeMux,也称为路由管理器)不能满足需求,因此在这里,需要借助一个第三方包 github.com/gorilla/mux 来实现需求。
处理函数都是先获取 http 请求包体数据,然后通过标准库 json 包将这些数据,解码(decode)需要的 store.Book 结构体实例,再通过 Store 接口对图书数据进行存储操作。如果是获取图书数据的请求,那么处理函数将通过 response 函数,把取出的图书数据编码到 http 响应的包体中,并返回给客户端。
把 BookStoreServer 内部的 http.Server 的运行,放置到一个单独的轻量级线程 Goroutine 中。这是因为,http.Server.ListenAndServe 会阻塞代码的继续运行,如果不把它放在单独的 Goroutine 中,后面的代码将无法得到执行
每个人都有潜在的能量,只是很容易被习惯所掩盖,被时间所迷离,被惰性所消磨~