使用 Go 1.22 和 http.ServeMux 构建 REST API | 作者: Shiju Varghese
使用 Go 1.22 和 http.ServeMux 构建 REST API
Go 1.22 引入了一个重要的新功能:http.ServeMux 现在支持通过 HTTP 方法映射 URI 模式。这一功能的实现并未对 ServeMux 类型的现有 API 造成任何破坏性更改。Handle 和 HandleFunc 方法的模式参数格式如下:
[METHOD ][HOST]/[PATH]
其中,METHOD、HOST 和 PATH 都是可选的。如果指定了 HTTP 方法,则必须在方法名后加一个空格。以下是一个简单的示例:
使用 ServeMux 映射 URI 模式
mux := http.NewServeMux()
mux.HandleFunc("GET /api/notes", GetAll)
mux.HandleFunc("POST /api/notes", Post)
在上述代码中,GET 和 POST 是 HTTP 谓词,分别用于处理 /api/notes 路径的 GET 和 POST 请求。如果未指定 HTTP 方法,仍然可以正常工作。
配置 ServeMux 路由器模式
以下代码展示了如何使用 HTTP 方法配置 ServeMux 路由器模式:
func initializeRoutes(h *apphttp.NoteHandler) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/notes", h.GetAll)
mux.HandleFunc("GET /api/notes/{id}", h.Get)
mux.HandleFunc("POST /api/notes", h.Post)
mux.HandleFunc("PUT /api/notes/{id}", h.Put)
mux.HandleFunc("DELETE /api/notes/{id}", h.Delete)
return mux
}
在上述代码中,不同的 HTTP 方法(如 GET、POST、PUT 和 DELETE)被映射到不同的 URI 模式。通过这种方式,可以轻松实现 RESTful API 的路由配置。
获取路由参数
ServeMux 提供了一个名为 PathValue 的方法,用于从请求中检索命名路径参数的值。例如,以下代码展示了如何获取名为 id 的路由参数:
// 获取路由参数 id
id := r.PathValue("id")
如果请求的路径与模式不匹配,或者模式中没有指定的通配符参数,PathValue 将返回空字符串。
创建 HTTP 服务器
以下代码展示了如何在 package main 中创建一个 HTTP 服务器,并配置路由:
package main
import (
"log"
"net/http" apphttp "github.com/shijuvar/gokit/examples/http-api/httpmux"
"github.com/shijuvar/gokit/examples/http-api/memstore"
)// 程序入口
func main() {
repo, err := memstore.NewInmemoryRepository() // 使用内存数据库
if err != nil {
log.Fatal("Error:", err)
}
h := &apphttp.NoteHandler{
Repository: repo, // 注入依赖
}
router := initializeRoutes(h) // 配置路由 server := &http.Server{
Addr: ":8080",
Handler: router,
}
log.Println("Listening...")
server.ListenAndServe() // 启动 HTTP 服务器
}func initializeRoutes(h *apphttp.NoteHandler) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/notes", h.GetAll)
mux.HandleFunc("GET /api/notes/{id}", h.Get)
mux.HandleFunc("POST /api/notes", h.Post)
mux.HandleFunc("PUT /api/notes/{id}", h.Put)
mux.HandleFunc("DELETE /api/notes/{id}", h.Delete)
return mux
}
HTTP 处理程序函数
以下代码定义了用于处理 Note 实体 CRUD 操作的 HTTP 处理程序函数:
// Delete 处理 HTTP DELETE 请求 – /api/notes/{id}
func (h NoteHandler) Delete(w http.ResponseWriter, r http.Request) {
id := r.PathValue("id")
if err := h.Repository.Delete(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
import (
"encoding/json"
"errors"
"net/http"
"github.com/shijuvar/gokit/examples/http-api/model"
)
// NoteHandler 组织了 Note 实体的 [CRUD](https://www.explinks.com/wiki/what-is-crud/) 操作 HTTP 处理函数
type NoteHandler struct {
Repository model.Repository // 持久化接口
}
// Post 处理 HTTP POST 请求 - /api/notes
func (h *NoteHandler) Post(w http.ResponseWriter, r *http.Request) {
var note model.Note
// 解码传入的 JSON 数据
err := json.NewDecoder(r.Body).Decode(¬e)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 创建 Note
if err := h.Repository.Create(note); err != nil {
if errors.Is(err, model.ErrNoteExists) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
}
// GetAll 处理 HTTP GET 请求 - /api/notes
func (h *NoteHandler) GetAll(w http.ResponseWriter, r *http.Request) {
// 获取所有 Notes
if notes, err := h.Repository.GetAll(); err != nil {
if errors.Is(err, model.ErrNotFound) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else {
j, err := json.Marshal(notes)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(j)
}
}
// Get 处理 HTTP GET 请求 - /api/notes/{id}
func (h *NoteHandler) Get(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if note, err := h.Repository.GetById(id); err != nil {
if errors.Is(err, model.ErrNotFound) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else {
w.Header().Set("Content-Type", "application/json")
j, err := json.Marshal(note)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.WriteHeader(http.StatusOK)
w.Write(j)
}
}
// Put 处理 HTTP PUT 请求 - /api/notes/{id}
func (h *NoteHandler) Put(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
var note model.Note
err := json.NewDecoder(r.Body).Decode(¬e)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := h.Repository.Update(id, note); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
// Delete 处理 HTTP DELETE 请求 - /api/notes/{id}
func (h *NoteHandler) Delete(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if err := h.Repository.Delete(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
通过以上代码示例,您可以轻松使用 Go 1.22 和 http.ServeMux 构建一个功能完善的 REST API。新版本的 ServeMux 提供了更灵活的路由配置方式,同时保持了简单易用的特点。
原文链接: https://shijuvar.medium.com/building-rest-apis-with-go-1-22-http-servemux-2115f242f02b
最新文章
- 使用 Go 1.22 和 http.ServeMux 构建 REST API | 作者: Shiju Varghese
- 掌握API端到端测试:全面指南
- Tesults博客:API自动化测试指南
- 介绍全新的Rust REST API客户端库
- DeepSeek R1 × 飞书多维表格赋能教育领域
- 深入解析什么是API安全
- 使用 C++ 和 Win32 API 创建 GUI 窗口应用程序:从零构建 Windows 桌面界面
- 一个平台对接所有API:企业级API集成解决方案
- 台湾可以用支付宝吗?:支付与收款指南
- 深入解读 API Gateway:设计原则、实践与最佳架构
- 什么是 LangSmith
- 为API网关构建ChatGPT自定义插件 – API7.ai