使用 Gorilla Mux 和 CockroachDB 编写可维护 RESTful API(下)

简介: 本文将使用功能强大的 Gorilla Mux、GORM 和 CockroachDB 编写可维护 RESTful API。

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 编写测试代码,测试并不一定完善,这些都可以给到读者一些优化思路。


相关文章
|
4天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
7天前
|
小程序 前端开发 API
小程序全栈开发中的RESTful API设计
【4月更文挑战第12天】本文探讨了小程序全栈开发中的RESTful API设计,旨在帮助开发者理解和掌握相关技术。RESTful API基于REST架构风格,利用HTTP协议进行数据交互,遵循URI、客户端-服务器架构、无状态通信、标准HTTP方法和资源表述等原则。在小程序开发中,通过资源建模、设计API接口、定义资源表述及实现接口,实现前后端高效分离,提升开发效率和代码质量。小程序前端利用微信API与后端交互,确保数据流通。掌握这些实践将优化小程序全栈开发。
|
16天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
20天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
14 4
|
22天前
|
安全 API 开发者
构建高效可扩展的RESTful API服务
在数字化转型的浪潮中,构建一个高效、可扩展且易于维护的后端API服务是企业竞争力的关键。本文将深入探讨如何利用现代后端技术栈实现RESTful API服务的优化,包括代码结构设计、性能调优、安全性强化以及微服务架构的应用。我们将通过实践案例分析,揭示后端开发的最佳实践,帮助开发者提升系统的响应速度和处理能力,同时确保服务的高可用性和安全。
25 3
|
29天前
|
缓存 前端开发 API
构建高效可扩展的RESTful API:后端开发的最佳实践
【2月更文挑战第30天】 在现代Web应用和服务端架构中,RESTful API已成为连接前端与后端、实现服务间通信的重要接口。本文将探讨构建一个高效且可扩展的RESTful API的关键步骤和最佳实践,包括设计原则、性能优化、安全性考虑以及错误处理机制。通过这些实践,开发者可以确保API的健壮性、易用性和未来的可维护性。
|
10天前
|
缓存 前端开发 API
API接口封装系列
API(Application Programming Interface)接口封装是将系统内部的功能封装成可复用的程序接口并向外部提供,以便其他系统调用和使用这些功能,通过这种方式实现系统之间的通信和协作。下面将介绍API接口封装的一些关键步骤和注意事项。
|
17天前
|
监控 前端开发 JavaScript
实战篇:商品API接口在跨平台销售中的有效运用与案例解析
随着电子商务的蓬勃发展,企业为了扩大市场覆盖面,经常需要在多个在线平台上展示和销售产品。然而,手工管理多个平台的库存、价格、商品描述等信息既耗时又容易出错。商品API接口在这一背景下显得尤为重要,它能够帮助企业在不同的销售平台之间实现商品信息的高效同步和管理。本文将通过具体的淘宝API接口使用案例,展示如何在跨平台销售中有效利用商品API接口,以及如何通过代码实现数据的统一管理。
|
29天前
|
安全 算法 API
产品经理必备知识——API接口
前言 在古代,我们的传输信息的方式有很多,比如写信、飞鸽传书,以及在战争中使用的烽烟,才有了著名的烽火戏诸侯,但这些方式传输信息的效率终究还是无法满足高速发展的社会需要。如今万物互联的时代,我通过一部手机就可以实现衣食住行的方方面面,比如:在家购物、远程控制家电、自动驾驶等等,背后都离不开我们今天要聊的API接口。
|
29天前
|
数据采集 JSON API
如何实现高效率超简洁的实时数据采集?——Python实战电商数据采集API接口
你是否曾为获取重要数据而感到困扰?是否因为数据封锁而无法获取所需信息?是否因为数据格式混乱而头疼?现在,所有这些问题都可以迎刃而解。让我为大家介绍一款强大的数据采集API接口。