REST API设计模式和反模式

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的代码片段来帮助说明这些概念。

相关推荐
编码浪子22 分钟前
构建一个rust生产应用读书笔记7-确认邮件2
开发语言·后端·rust
昙鱼33 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
白宇横流学长40 分钟前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
kirito学长-Java1 小时前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端
程序猿-瑞瑞1 小时前
24 go语言(golang) - gorm框架安装及使用案例详解
开发语言·后端·golang·gorm
组合缺一1 小时前
Solon v3.0.5 发布!(Spring 可以退休了吗?)
java·后端·spring·solon
猿来入此小猿1 小时前
基于SpringBoot在线音乐系统平台功能实现十二
java·spring boot·后端·毕业设计·音乐系统·音乐平台·毕业源码
愤怒的代码2 小时前
Spring Boot对访问密钥加解密——HMAC-SHA256
java·spring boot·后端
栗豆包2 小时前
w118共享汽车管理系统
java·spring boot·后端·spring·tomcat·maven
万亿少女的梦1682 小时前
基于Spring Boot的网络购物商城的设计与实现
java·spring boot·后端