REST API设计模式和反模式

TimLiuDream · · 909 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

RESTful API已经成为构建现代网络应用的事实标准。它们允许一个灵活和可扩展的架构,可以很容易地被广泛的客户端所消费。然而,设计一个既健壮又可维护的REST API是很有挑战性的,特别是对于刚入行的开发者。 在这篇文章中,我们将探讨一些常见的REST API设计模式和开发者应该注意的反模式。我们还将提供Golang和Open API Schema的代码片段来帮助说明这些概念。 # REST API设计模式 **1.以资源为导向的架构(ROA)** 面向资源的架构(ROA)是一种设计模式,强调资源在RESTful API中的重要性。资源是RESTful API的关键构件,它们应该被设计成易于消费和操作的方式。 在Golang中实现ROA的一种方式是使用`gorilla/mux`包进行路由。这里有一个例子: ```go r := mux.NewRouter() r.HandleFunc("/users/{id}", getUser).Methods("GET") r.HandleFunc("/users", createUser).Methods("POST") r.HandleFunc("/users/{id}", updateUser).Methods("PUT") r.HandleFunc("/users/{id}", deleteUser).Methods("DELETE") ``` 在Open API Schema中,你可以使用`path`参数来定义资源。下面是一个例子: ```go paths: /users/{id}: get: … put: … delete: … /users: post: … ``` **2. HATEOAS** 超媒体作为应用状态的引擎(HATEOAS)是一种设计模式,允许客户动态地浏览RESTful API。API提供超媒体链接,客户可以按照这些链接来发现资源并与之互动。 为了在GoLang中实现`HATEOAS`,你可以使用`go-jsonapi`包。这里有一个例子: ```go type User struct { ID string `json:"id"` Name string `json:"name"` Links *Links `json:"links,omitempty"` } type Links struct { Self *Link `json:"self,omitempty"` } type Link struct { Href string `json:"href,omitempty"` } func getUser(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["id"] user := User{ID: userID, Name: "John Doe"} user.Links = &Links{ Self: &Link{Href: fmt.Sprintf("/users/%s", userID)}, } jsonapi.MarshalOnePayload(w, &user) } ``` 在Open API Schema中,你可以使用`links`参数来定义超媒体链接。这里有一个例子: ```go paths: /users/{id}: get: responses: '200': content: application/json: schema: $ref: '#/components/schemas/User' links: self: href: '/users/{id}' ``` # REST API反模式 1.RPC式的API 远程过程调用(RPC)风格的API是RESTful API设计中一个常见的反模式。RPC风格的API暴露了直接映射到底层实现的方法,而不是专注于资源。 下面是一个GoLang中RPC风格API的例子: ```go func getUser(w http.ResponseWriter, r *http.Request) { userID := r.FormValue("id") user := userService.GetUser(userID) json.NewEncoder(w).Encode(user) } ``` 在Open API Schema中,你可以使用`operationId`参数来定义RPC风格的API。下面是一个例子: ```go paths: /users: get: operationId: getUser ``` 2.过度的工程设计 过度工程是RESTful API设计中另一个常见的反模式。当开发者试图预测每一个可能的用例并建立一个复杂的API来适应它们时,就会出现过度设计。 这里有一个Golang中过度工程的例子: ```go func getUser(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["id"] user, err := userService.GetUser(userID) if err != nil { handleError(w, err) return } json.NewEncoder(w).Encode(user) } func createUser(w http.ResponseWriter, r *http.Request) { var user User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { handleError(w, err) return } user.ID = uuid.New().String() user.CreatedAt = time.Now() user.UpdatedAt = time.Now() err = userService.CreateUser(user) if err != nil { handleError(w, err) return } json.NewEncoder(w).Encode(user) } func updateUser(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["id"] var user User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { handleError(w, err) return } user.ID = userID user.UpdatedAt = time.Now() err = userService.UpdateUser(user) if err != nil { handleError(w, err) return } json.NewEncoder(w).Encode(user) } func deleteUser(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["id"] err := userService.DeleteUser(userID) if err != nil { handleError(w, err) return } w.WriteHeader(http.StatusNoContent) } func handleError(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, err. Error()) } ``` 在Open API Schema中,你可以使用`x-go-genie`扩展定义过度工程。这里有一个例子: ```go paths: /users/{id}: get: x-go-genie: serviceName: UserService methodName: GetUser put: x-go-genie: serviceName: UserService methodName: UpdateUser delete: x-go-genie: serviceName: UserService methodName: DeleteUser /users: post: x-go-genie: serviceName: UserService methodName: CreateUser ``` # 总结 设计一个既健壮又可维护的RESTful API可能具有挑战性,但通过遵循最佳实践并避免常见的反模式,开发人员可以创建易于消费和操作的API。在这篇文章中,我们探讨了一些常见的REST API设计模式和反模式,并提供了GoLang和Open API Schema的代码片段来帮助说明这些概念。 > 关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

909 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传