每日一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君”回复“源码”获取源码
如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!