
使用NestJS和Prisma構建REST API:身份驗證
GET /users
獲取指定用戶:
GET /users/1
創建用戶:
POST /users
{
"name": "John",
"age": 30
}
更新用戶:
PUT /users/1
{
"name": "John",
"age": 31
}
刪除用戶:
DELETE /users/1
它的優點在于:
在RESTful API中,我們使用標準的接口比如 /users 來操作資源,然后通過過濾條件或資源標識來指定操作哪些資源。例如:
獲取所有用戶: GET /users
創建一個產品: POST /users?type=product
更新一條訂單: PUT /users/1?type=order
刪除一篇文章: DELETE /users/2?type=post
這樣設計的好處是接口簡單易用,客戶端可以通過一套標準接口來訪問不同類型的資源,只需要在請求中提供必要的過濾條件或資源標識。
HATEOAS是代表”Hypermedia As The Engine Of Application State”的首字母縮寫。它是RESTful API的一個重要原則,意思是應用狀態應驅動由超媒體來定義和控制。也就是說,RESTful API應該提供一系列超鏈接來連接相關資源,并通過這些鏈接來定義客戶端的工作流程與導航方式。客戶端不需要事先知道這些鏈接,只需要與API進行交互,并根據獲得的鏈接來獲取更多信息或調整狀態。一個典型的例子是Github的API。例如,當我們獲取一個用戶資源時:
{
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
}
這個用戶資源提供了許多鏈接,分別指向:
設計微服務RPC接口時,可以遵循RESTful的理念和規范,使RPC接口易于理解和使用,客戶端可以像調用REST API一樣調用這些接口。
比如 設計一個商城系統,有訂單,用戶,支付,商品,系統內部采用微服務架構,使用gRPC協議,具體的設計可以如下:
1. 資源導向
定義訂單服務OrderService,用戶服務UserService,商品服務ProductService等。
2. 使用服務方法對應CRUD
訂單服務:
CreateOrder(Order) 創建訂單,對應POST /orders
GetOrder(OrderId) 獲取訂單,對應GET /orders/{id}
UpdateOrder(Order) 更新訂單,對應PUT /orders/{id}
DeleteOrder(OrderId) 刪除訂單,對應DELETE /orders/{id}
用戶服務:
CreateUser(User) 創建用戶,對應POST /users
GetUser(UserId) 獲取用戶,對應GET /users/{id}
UpdateUser(User) 更新用戶,對應PUT /users/{id}
DeleteUser(UserId) 刪除用戶,對應DELETE /users/{id}
3. 統一接口格式
每個服務使用如下格式定義接口
service OrderService {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
rpc GetOrder(GetOrderRequest) returns (GetOrderResponse) {}
// 其他方法...
}
message CreateOrderRequest {
// 請求參數
}
message CreateOrderResponse {
// 返回結果
}
4. 無狀態
服務端不會儲存客戶端狀態,每次請求必須包含所有必要信息。
5. Get接口返回全部信息
返回全部信息可以防止不同需求需要獲取某個資源(比如訂單)不同字段信息從而每次新定義一個接口造成接口數量急劇膨脹泛濫降低可維護性。如果某些面向客戶端接口(協議)只需要特定字段,在網關層進行信息裁剪。
6.錯誤處理
?在RESTful API中,我們常用HTTP狀態碼表示錯誤,并在響應體中返回詳細的錯誤信息。在gRPC接口中,我們可以返回非空的錯誤信息來表示錯誤:
// 錯誤信息
message Error {
int err_code = 1; //錯誤碼
string message = 2; // 錯誤描述
}
// 創建訂單接口
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {}
// 錯誤響應
message CreateOrderResponse {
Error error = 1; // 包含錯誤信息的Error消息
}
客戶端調用此接口,如果返回的CreateOrderResponse中包含error信息,就表示調用失敗,可以獲取error消息中的詳細失敗原因。
7. 元數據(Labels)
?在RESTful API中,我們可以使用請求頭中的元數據來提供調用相關的上下文信息。在gRPC接口中,我們可以在請求消息和響應消息中包含label字段:
message CreateOrderRequest {
// 請求參數...
// 元數據
map<string, string> labels = 10;
}
message CreateOrderResponse {
// 返回結果...
// 元數據
map<string, string> labels = 10;
}
labels是一個字符串到字符串的映射,可以包含諸如:
這樣設計的RPC接口具有如下優點:
所以,總體來說,這是一種模型比較清晰的RPC接口設計思路,可以讓RPC的接口設計更加符合微服務架構下的實踐,也更易于被人理解和使用。
本文章轉載微信公眾號@吃瓜技術派