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


相关文章
|
10月前
|
XML JSON API
识别这些API接口定义(http,https,api,RPC,webservice,Restful api ,OpenAPI)
本内容介绍了API相关的术语分类,包括传输协议(HTTP/HTTPS)、接口风格(RESTful、WebService、RPC)及开放程度(API、OpenAPI),帮助理解各类API的特点与应用场景。
|
12月前
|
缓存 安全 API
RESTful与GraphQL:电商API接口设计的技术细节与适用场景
本文对比了RESTful与GraphQL这两种主流电商API接口设计方案。RESTful通过资源与HTTP方法定义操作,简单直观但可能引发过度或欠获取数据问题;GraphQL允许客户端精确指定所需字段,提高灵活性和传输效率,但面临深度查询攻击等安全挑战。从性能、灵活性、安全性及适用场景多维度分析,RESTful适合资源导向场景,GraphQL则适用于复杂数据需求。实际开发中需根据业务特点选择合适方案,或结合两者优势,以优化用户体验与系统性能。
|
12月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
11月前
|
缓存 边缘计算 前端开发
从业务需求到技术栈:电商API选型RESTful还是GraphQL?这5个维度帮你决策
在数字经济时代,电商平台的竞争已延伸至用户体验与系统效能。作为连接前后端及各类服务的核心,API接口的架构设计至关重要。本文对比RESTful与GraphQL两大主流方案,从电商场景出发,分析两者的技术特性、适用场景与选型逻辑,帮助开发者根据业务需求做出最优选择。
|
XML JSON API
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
|
机器学习/深度学习 设计模式 API
Python 高级编程与实战:构建 RESTful API
本文深入探讨了使用 Python 构建 RESTful API 的方法,涵盖 Flask、Django REST Framework 和 FastAPI 三个主流框架。通过实战项目示例,详细讲解了如何处理 GET、POST 请求,并返回相应数据。学习这些技术将帮助你掌握构建高效、可靠的 Web API。
|
JSON JavaScript 前端开发
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
420 12
|
监控 安全 API
深入浅出:构建高效RESTful API的最佳实践
在数字化时代,API已成为连接不同软件和服务的桥梁。本文将带你深入了解如何设计和维护一个高效、可扩展且安全的RESTful API。我们将从基础概念出发,逐步深入到高级技巧,让你能够掌握创建优质API的关键要素。无论你是初学者还是有经验的开发者,这篇文章都将为你提供实用的指导和启示。让我们一起探索API设计的奥秘,打造出色的后端服务吧!
|
API 网络架构 UED
构建RESTful API的最佳实践
【8月更文挑战第54天】在数字化时代,RESTful API已成为连接不同软件系统、提供数据服务的关键桥梁。本文将深入探讨如何构建高效、可维护的RESTful API,涵盖设计原则、安全策略和性能优化等关键方面。通过具体代码示例,我们将一步步展示如何实现一个简洁、直观且功能强大的API。无论你是新手还是有经验的开发者,这篇文章都将为你提供宝贵的指导和启示。
243 33
|
SQL 缓存 测试技术
构建高性能RESTful API:最佳实践与避坑指南###
—— 本文深入探讨了构建高性能RESTful API的关键技术要点,从设计原则、状态码使用、版本控制到安全性考虑,旨在为开发者提供一套全面的最佳实践框架。通过避免常见的设计陷阱,本文将指导你如何优化API性能,提升用户体验,确保系统的稳定性和可扩展性。 ###
457 12