每日一Go-17、Go语言实战-设计RESTful API

43 阅读3分钟

每日一Go-17、Go语言实战-设计RESTful API

1、什么是REFTful API?

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。RESTful API就是基于REST风格架构的API。

1.1 使用HTTP方法表示动作

GET:查询
POST:新增
PUT:整体更新
PATCH:局部更新
DELETE:删除

1.2 使用资源(Resource)的“名词”作为URL

/books       -> 书籍列表
/books/1     -> id为1的书籍

1.3 返回标准的HTTP状态码

200 OK
201 Created
400 Bad Request
404 Not Found
500 Internal Server Error

1.4 使用JSON作为默认数据格式

{
  "code": 200,
  "data": [
      {
        "id":1,
        "name:"Coding君"
      }
   ]
}

2、用Go实战构建一个简单的RESTful API

package main
import (
    "encoding/json"
    "log"
    "net/http"
    "strconv"
    "strings"
)
// 书的定义
type Book struct {
    ID     int    `json:"id"`
    Title  string `json:"title"`  //书名
    Author string `json:"author"` //作者
}
// 这里存放所有的书籍
var books = []Book{}
var nextID = 1
func main() {
    http.HandleFunc("/books", booksHandler)
    http.HandleFunc("/books/", bookHandler)
    log.Println("Server running at http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
// ------ 书籍列表(/books)------
func booksHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        getBooks(w, r)
    case "POST":
        createBook(w, r)
    default:
        http.Error(w, "方法错误", http.StatusMethodNotAllowed)
    }
}
// ------ 单个书籍(/books/{id})------
func bookHandler(w http.ResponseWriter, r *http.Request) {
    idStr := strings.TrimPrefix(r.URL.Path, "/books/")
    id, err := strconv.Atoi(idStr)
    if err != nil {
        http.Error(w, "没有传id", http.StatusBadRequest)
        return
    }
    switch r.Method {
    case "GET":
        getBook(w, r, id)
    case "PUT":
        updateBook(w, r, id)
    case "DELETE":
        deleteBook(w, r, id)
    default:
        http.Error(w, "方法错误", http.StatusMethodNotAllowed)
    }
}
// ------ 处理函数 ------
func getBooks(w http.ResponseWriter, _ *http.Request) {
    json.NewEncoder(w).Encode(books)
}
func createBook(w http.ResponseWriter, r *http.Request) {
    var b Book
    if err := json.NewDecoder(r.Body).Decode(&b); err != nil {
        http.Error(w, "非法请求", http.StatusBadRequest)
        return
    }
    b.ID = nextID
    nextID++
    books = append(books, b)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(b)
}
func getBook(w http.ResponseWriter, _ *http.Request, id int) {
    for _, b := range books {
        if b.ID == id {
            json.NewEncoder(w).Encode(b)
            return
        }
    }
    http.NotFound(w, nil)
}
func updateBook(w http.ResponseWriter, r *http.Request, id int) {
    var updated Book
    if err := json.NewDecoder(r.Body).Decode(&updated); err != nil {
        http.Error(w, "非法请求", http.StatusBadRequest)
        return
    }
    for i, b := range books {
        if b.ID == id {
            updated.ID = id
            books[i] = updated
            json.NewEncoder(w).Encode(updated)
            return
        }
    }
    http.NotFound(w, nil)
}
func deleteBook(w http.ResponseWriter, _ *http.Request, id int) {
    for i, b := range books {
        if b.ID == id {
            books = append(books[:i], books[i+1:]...)
            w.WriteHeader(http.StatusOK)
            w.Write([]byte("删除成功"))
            return
        }
    }
    http.NotFound(w, nil)
}

3、测试方法

1.1 启动服务

$ go run .Server running at http://localhost:8080

1.2 新增书籍(POST)

$ curl -X POST -H "Content-Type: application/json" \                             
-d '{"title":"Golang","author":"CodingJun"}' \                                   
http://localhost:8080/books                                                      
{"id":1,"title":"Golang","author":"CodingJun"}  

$ curl -X POST -H "Content-Type: application/json" \                             
-d '{"title":"Python","author":"CodingJun"}' \                                   
http://localhost:8080/books                                                      
{"id":2,"title":"Python","author":"CodingJun"}   

1.3 查询全部(GET)

$ curl http://localhost:8080/books                                               
[
  {"id":1,"title":"Golang","author":"CodingJun"},
  {"id":2,"title":"Python","author":"CodingJun"}
]    

1.4 查询单个(GET)

$ curl http://localhost:8080/books/1                                             
{"id":1,"title":"Golang","author":"CodingJun"}  

1.5 更新(PUT)

$ curl -X PUT -H "Content-Type: application/json" \                              
-d '{"title":"Golang per day","author":"CodingJun"}' \                           
http://localhost:8080/books/1                                                    
{"id":1,"title":"Golang per day","author":"CodingJun"}    
$ curl http://localhost:8080/books                                               
[{"id":1,"title":"Golang per day","author":"CodingJun"},{"id":2,"title":"Python",
"author":"CodingJun"}]   

1.6 删除(DELETE)

$ curl -X DELETE http://localhost:8080/books/1
删 除 成 功    
$ curl http://localhost:8080/books
[{"id":2,"title":"Python","author":"CodingJun"}] 

4、RESTful API设计建议

原则描述
URL用名词/users 不用 /getUsers
状态码明确201新建成功、404未找到
JSON一致性字段风格统一(全小写下划线)
分层设计Handler->Service->Repository
日志和错误处理避免panic,统一输出格式

5、人生真理

把人生当成一个不断 CRUD 的系统——勇于开始(POST),善于觉察(GET),持续改进(PUT/PATCH),学会放下(DELETE),并把所有经验写进自己的“人生文档”。那么你将永远处于成长、清晰、轻盈、向上的状态。

源码地址

1、公众号“Codee君”回复“源码”获取源码

2、pan.baidu.com/s/1B6pgLWfS… 


如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!