RESTful API曾经成为构建古代网络应用的事实标准。它们容许一个灵便和可扩大的架构,能够很容易地被宽泛的客户端所生产。然而,设计一个既强壮又可保护的REST API是很有挑战性的,特地是对于刚入行的开发者。
在这篇文章中,咱们将探讨一些常见的REST API设计模式和开发者应该留神的反模式。咱们还将提供Golang和Open API Schema的代码片段来帮忙阐明这些概念。
REST API设计模式
1.以资源为导向的架构(ROA)
面向资源的架构(ROA)是一种设计模式,强调资源在RESTful API中的重要性。资源是RESTful API的要害构件,它们应该被设计成易于生产和操作的形式。
在Golang中实现ROA的一种形式是应用gorilla/mux
包进行路由。这里有一个例子:
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
参数来定义资源。上面是一个例子:
paths:
/users/{id}:
get:
…
put:
…
delete:
…
/users:
post:
…
2. HATEOAS
超媒体作为利用状态的引擎(HATEOAS)是一种设计模式,容许客户动静地浏览RESTful API。API提供超媒体链接,客户能够依照这些链接来发现资源并与之互动。
为了在GoLang中实现HATEOAS
,你能够应用go-jsonapi
包。这里有一个例子:
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
参数来定义超媒体链接。这里有一个例子:
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的例子:
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。上面是一个例子:
paths:
/users:
get:
operationId: getUser
2.适度的工程设计
适度工程是RESTful API设计中另一个常见的反模式。当开发者试图预测每一个可能的用例并建设一个简单的API来适应它们时,就会呈现适度设计。
这里有一个Golang中适度工程的例子:
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
扩大定义适度工程。这里有一个例子:
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的代码片段来帮忙阐明这些概念。
发表回复