Golang中net/http包实现RESTful API的实践指南

Golang中net/http包实现RESTful API的实践指南 你好,我是初学者,想使用 net/http 构建我的 RESTful API。查阅了网上的资料后,

func TodoHandler(w http.ResponseWriter, r *http.Request) {
	var err error
	switch r.Method {
	case "GET":
		err = getController(w, r)
	case "POST":
		err = postController(w, r)
	case "PUT":
		err = putController(w, r)
	case "DELETE":
		err = delController(w, r)
	}
	if err != nil {
		panic(err)
	}
}
func getController(w http.ResponseWriter, r *http.Request) error {
	id, err := strconv.Atoi(path.Base(r.URL.Path))
	if err != nil {
		return err
	}
	todo, err := model.GetTodo(id)
	if err != nil {
		return err
	}
	data, err := json.Marshal(&todo)
	if err != nil {
		return err
	}
	fmt.Fprint(w, string(data))
	return nil
}

func postController(w http.ResponseWriter, r *http.Request) error {
	len := r.ContentLength
	body := make([]byte, len)
	r.Body.Read(body)
	todo := new(model.Todo)
	json.Unmarshal(body, &todo)
	err := todo.Create()
	if err != nil {
		return err
	}
	return nil
}
...

这是我目前完成的部分,但我不知道如何像网上其他 RESTful API 那样进行扩展和设计。暂时不考虑使用第三方包。


更多关于Golang中net/http包实现RESTful API的实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

如何以这种方式扩展,使其看起来像一个真正的 RESTful API

更多关于Golang中net/http包实现RESTful API的实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


您也可以使用Mux轻松创建美观的API 😊

mu1er:

像互联网上其他 RESTful API 那样进行扩展和设计

你指的是什么意思?

这些代码没有错误。我的意思是,如果遵循这种设计,它算是 RESTful API 吗?我是这个领域的新手,想要学习一下。

什么是真正的RESTful API?这是一个非常广泛的话题,涉及如何建模REST资源、要使用何种表示形式、是否尝试实现HATEOAS等等。

您是否有关于代码及其执行或未执行的特定操作的具体问题?

代码中可能有些细节需要调整,但总的来说这就是构建REST接口的方式。将路径和方法映射到处理程序,在处理程序中执行必要操作并返回JSON等响应。

func main() {
    fmt.Println("hello world")
}

如果你没有关于Go语言的问题,这里就不讨论这个话题了。

如果你想了解REST,网上有很多资源可以阅读。但请注意,对于什么是"真正的"REST存在很多不同观点。可以看看:

以下是一个基于标准库 net/http 的 RESTful API 完整实现示例,包含路由解析、错误处理和 JSON 响应:

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"
)

// Todo 数据结构
type Todo struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Done  bool   `json:"done"`
}

// 模拟数据存储
var todos = map[int]*Todo{}
var idCounter = 1

// 统一 JSON 响应
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(data)
}

// 错误响应
func writeError(w http.ResponseWriter, status int, message string) {
	writeJSON(w, status, map[string]string{"error": message})
}

// 路由解析器
type Router struct {
	routes map[string]http.HandlerFunc
}

func NewRouter() *Router {
	return &Router{
		routes: make(map[string]http.HandlerFunc),
	}
}

func (r *Router) Handle(method, path string, handler http.HandlerFunc) {
	r.routes[method+" "+path] = handler
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// 处理 CORS 预检请求
	if req.Method == "OPTIONS" {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
		return
	}

	path := req.URL.Path
	method := req.Method

	// 路由匹配逻辑
	switch {
	case method == "GET" && path == "/todos":
		r.handleGetTodos(w, req)
	case method == "GET" && strings.HasPrefix(path, "/todos/"):
		r.handleGetTodo(w, req)
	case method == "POST" && path == "/todos":
		r.handleCreateTodo(w, req)
	case method == "PUT" && strings.HasPrefix(path, "/todos/"):
		r.handleUpdateTodo(w, req)
	case method == "DELETE" && strings.HasPrefix(path, "/todos/"):
		r.handleDeleteTodo(w, req)
	default:
		writeError(w, http.StatusNotFound, "Not Found")
	}
}

// 获取所有 Todo
func (r *Router) handleGetTodos(w http.ResponseWriter, req *http.Request) {
	var result []*Todo
	for _, todo := range todos {
		result = append(result, todo)
	}
	writeJSON(w, http.StatusOK, result)
}

// 获取单个 Todo
func (r *Router) handleGetTodo(w http.ResponseWriter, req *http.Request) {
	idStr := strings.TrimPrefix(req.URL.Path, "/todos/")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		writeError(w, http.StatusBadRequest, "Invalid ID")
		return
	}

	todo, exists := todos[id]
	if !exists {
		writeError(w, http.StatusNotFound, "Todo not found")
		return
	}

	writeJSON(w, http.StatusOK, todo)
}

// 创建 Todo
func (r *Router) handleCreateTodo(w http.ResponseWriter, req *http.Request) {
	var todo Todo
	if err := json.NewDecoder(req.Body).Decode(&todo); err != nil {
		writeError(w, http.StatusBadRequest, "Invalid JSON")
		return
	}

	todo.ID = idCounter
	idCounter++
	todos[todo.ID] = &todo

	writeJSON(w, http.StatusCreated, todo)
}

// 更新 Todo
func (r *Router) handleUpdateTodo(w http.ResponseWriter, req *http.Request) {
	idStr := strings.TrimPrefix(req.URL.Path, "/todos/")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		writeError(w, http.StatusBadRequest, "Invalid ID")
		return
	}

	existing, exists := todos[id]
	if !exists {
		writeError(w, http.StatusNotFound, "Todo not found")
		return
	}

	var updates Todo
	if err := json.NewDecoder(req.Body).Decode(&updates); err != nil {
		writeError(w, http.StatusBadRequest, "Invalid JSON")
		return
	}

	if updates.Title != "" {
		existing.Title = updates.Title
	}
	existing.Done = updates.Done

	writeJSON(w, http.StatusOK, existing)
}

// 删除 Todo
func (r *Router) handleDeleteTodo(w http.ResponseWriter, req *http.Request) {
	idStr := strings.TrimPrefix(req.URL.Path, "/todos/")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		writeError(w, http.StatusBadRequest, "Invalid ID")
		return
	}

	if _, exists := todos[id]; !exists {
		writeError(w, http.StatusNotFound, "Todo not found")
		return
	}

	delete(todos, id)
	writeJSON(w, http.StatusNoContent, nil)
}

func main() {
	router := NewRouter()

	// 添加示例数据
	todos[1] = &Todo{ID: 1, Title: "Learn Go", Done: false}
	todos[2] = &Todo{ID: 2, Title: "Build REST API", Done: false}
	idCounter = 3

	fmt.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", router))
}

这个实现提供了以下功能:

  1. 完整的 CRUD 操作

    • GET /todos - 获取所有待办事项
    • GET /todos/{id} - 获取单个待办事项
    • POST /todos - 创建新待办事项
    • PUT /todos/{id} - 更新待办事项
    • DELETE /todos/{id} - 删除待办事项
  2. 路由解析:使用路径前缀匹配来处理动态路由

  3. 错误处理:统一的错误响应格式

  4. JSON 处理:自动的 JSON 序列化和反序列化

  5. CORS 支持:处理跨域请求

测试示例:

# 获取所有 todos
curl http://localhost:8080/todos

# 创建新 todo
curl -X POST -H "Content-Type: application/json" -d '{"title":"New Todo"}' http://localhost:8080/todos

# 更新 todo
curl -X PUT -H "Content-Type: application/json" -d '{"title":"Updated","done":true}' http://localhost:8080/todos/1

# 删除 todo
curl -X DELETE http://localhost:8080/todos/1

这个架构可以轻松扩展新的端点,只需在 ServeHTTP 方法中添加新的路由匹配逻辑即可。

回到顶部