3.3 handler.go
回到 mybook 文件夹下,创建 handler.go
:
package main import ( "encoding/json" "net/http" "mybook/model" "github.com/gorilla/mux" "gorm.io/gorm" ) type Server struct { db *gorm.DB } type UpdateBook struct { Price float64 `json:"price"` Description string `json:"decription"` Category string `json:"category"` } func NewServer(db *gorm.DB) *Server { return &Server{db: db} } func (s *Server) RegisterRouter(router *mux.Router) { router.HandleFunc("/books", s.getBooks) router.HandleFunc("/book/{id}", s.getBook).Methods("GET") router.HandleFunc("/book", s.createBook).Methods("POST") router.HandleFunc("/book/{id}", s.updateBook).Methods("PUT") router.HandleFunc("/book/{id}", s.deleteBook).Methods("DELETE") } func (s *Server) getBooks(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json;charset=UTF-8") var books []model.Book if err := s.db.Find(&books).Error; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(books) } func (s *Server) createBook(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") var book model.Book if err := json.NewDecoder(r.Body).Decode(&book); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } newBook := model.Book{Price: book.Price, Description: book.Description, Category: book.Category} if err := s.db.Create(newBook).Error; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(newBook) } func (s *Server) getBook(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") var book model.Book vars := mux.Vars(r) id := vars["id"] if err := s.db.Where("id = ?", id).First(&book).Error; err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(book) } func (s *Server) updateBook(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") var updateBook UpdateBook var book model.Book vars := mux.Vars(r) id := vars["id"] if err := json.NewDecoder(r.Body).Decode(&updateBook); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := s.db.Where("id = ?", id).First(&book).Error; err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } if err := s.db.Model(&book).Updates(&model.Book{ Price: updateBook.Price, Description: updateBook.Description, Category: updateBook.Category}).Error; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(book) } func (s *Server) deleteBook(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") var book model.Book vars := mux.Vars(r) id := vars["id"] if err := s.db.Where("id = ?", id).First(&book).Error; err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } if err := s.db.Delete(&book).Error; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode("Book Deleted Successfully!") }
3.4 main.go
在 main.go
中,我们初始化数据库,创建一个路由器实例,将变量 db 作为参数传递给我们的服务器初始化,然后将路由器实例作为参数传递给方法 registryRouter()
。然后,我们使用侦听器来运行服务器。
package main import ( "log" "net/http" "github.com/gorilla/mux" "mybook/model" ) func main() { db, err := model.SetupDB() if err != nil { log.Println("Failed setting up database") } router := mux.NewRouter() server := NewServer(db) server.RegisterRouter(router) log.Fatal(http.ListenAndServe(":8000", router)) }
当写完所有的程序后,运行 go run .
命令,启动成功如下:
此时,运行 cockcoach sql
进入数据库命令行,然后运行 show tables;
命令,可以看到在默认数据库 defaultdb
中已经生成一个 books 数据库表,如下所示:
我们执行 select * from books
查看我们生成的表信息:
可以看到已经生成了我们定义的字段 id、name、author、description、price、category 以外,GORM 还默认帮忙增加了 created_at
(创建时间)、updated_at
(更新时间)和 deleted_at
(删除时间)三个字段。
4 API 测试
为了方便我们测试这个 book 应用的 API 功能正常,我们将利用 APIfox 工具来进行测试。先在数据库中新增一条记录,如下:
INSERT INTO books (id, name, author, description, price, category)VALUES(1, 'Go程序设计语言(英文版)', '艾伦A.A.多诺万 (Alan A.A.Donovan) / 布莱恩W.柯尼汉 (Brian W.Kemighan)', '被誉为 Go 语言圣经的书,非常值得一读', 79.00, 'Golang');
复制代码
获取书籍清单:/books
测试
插入成功,我们访问后台 http://127.0.0.1:8000/books
路径,可以看到如下成功,说明获取书籍清单的 API 是成功的,恭喜。
接下来为了测试,下载 Linux 版本的 Apifox 帮助我们快速测试其他接口。
获取一本书籍:/book/1
测试
总结
本文利用 Go 语言中非常实用的 Gorilla Mux 和 GORM 库、结合分布式 CockroachDB 数据库编写了一个简易的图书的 Restful API,最后通过 Apifox 测试工具验证了服务器 API 的正确。
显然本文还是有很多不足,比如并没有充分利用到 CockroachDB 数据库的分布式特性,而且没有为 API 编写测试代码,测试并不一定完善,这些都可以给到读者一些优化思路。