【全棧修煉】RESTful架構及實踐 修煉寶典

RESTful API

1、概念介紹

1. REST 概念

REST:(Representational State Transfer)即表現層狀態轉換,定義了資源的通用訪問格式,是一種網絡應用程序的設計風格開發方式html

在概念中,須要理解如下幾個名稱:前端

  1. 資源(Resource)

服務器上獲取到的東西任何資源,一條用戶記錄,一個用戶的密碼,一張圖片等等都是。node

  1. 資源的表述(Representation)

資源格式,是 HTML、XML、JSON、純文本、圖片等等,能夠用各類各樣的格式來表述你獲取到的資源。git

  1. 狀態轉移(State Transfer)

URL定位資源,用 HTTP 動詞(GET,POST,DELETE,DETC)描述操做。操做是動詞,資源是名詞。github

  1. 統一接口(Uniform Interface)

即經過統一的接口對資源進行操做。spring

2. REST 特色

REST 一般基於使用 HTTPURI ,和 XML 以及 HTML 這些現有的普遍流行的協議和標準,每一種 URI 表明一種資源。express

REST 一般使用 JSON 數據格式。json

REST 基本架構的四個方法:api

  • GET - 用於獲取數據
  • PUT - 用於更新或添加數據
  • DELETE - 用於刪除數據
  • POST - 用於添加數據

下面會經過一個場景介紹。瀏覽器

3. REST 優勢

  • 可更高效利用緩存來提升響應速度
  • 通信自己的無狀態性可讓不一樣的服務器的處理一系列請求中的不一樣請求,提升服務器的擴展性
  • 瀏覽器便可做爲客戶端,簡化軟件需求
  • 相對於其餘疊加在HTTP協議之上的機制,REST的軟件依賴性更小
  • 不須要額外的資源發現機制
  • 在軟件技術演進中的長期的兼容性更好

2、實例介紹

REST 定義了資源的通用訪問格式,接下來一個消費者爲實例,介紹 RESTful API 定義:

  1. 獲取全部 users
GET /api/users
  1. 獲取指定 id 的 users
GET /api/users/100
  1. 新建一條 users 記錄
POST /api/users
  1. 更新一條 users 記錄
PUT /api/users/100
  1. 刪除一條 users 記錄
DELETE /api/users/100
  1. 獲取一個 users 的全部消費帳單
GET  /api/users/100/bill
  1. 獲取一個 user 指定時間的消費帳單
GET  /api/users/100/bill?from=201910&to=201911

以上其中 RESTful 風格 API 幾乎包含常見業務狀況。

3、Nodejs 實現 RESTful API

1. 初始化 mock 數據

本案例使用 mock 數據來演示,以下:

{
   "user1" : {
      "name" : "leo",
      "password" : "123456",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "pingan8787",
      "password" : "654321",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "robin",
      "password" : "888888",
      "profession" : "clerk",
      "id": 3
   }
}

咱們將實現如下 RESTful API :

2. 獲取用戶列表

這一步咱們會建立 RESTful API 中的 /users,使用 GET 來讀取用戶的信息列表

// index.js
const express = require('express');
const app = express();
const fs = require("fs");

// 定義 讀取用戶的信息列表 的接口
app.get('/users', (req, res) => {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       console.log( data );
       res.end( data );
   });
})

const server = app.listen(8081, function () {
    const {address, port} = server.address();
    console.log("server run in: http://%s:%s", address, port);
})

3. 添加用戶

這一步咱們會建立 RESTful API 中的 /users,使用 POST 來添加用戶記錄

// index.js
// 省略以前文件 只展現須要實現的接口

// mock 一條要新增的數據
const user = {
   "user4" : {
      "name" : "pingan",
      "password" : "password4",
      "profession" : "teacher",
      "id": 4
   }
}

// 定義 添加用戶記錄 的接口
app.post('/users', (req, res) => {
   // 讀取已存在的數據
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       data["user4"] = user["user4"];
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

4. 獲取用戶詳情

這一步咱們在 RESTful API 中的 URI 後面加上 /users/:id,使用 GET 來獲取指定用戶詳情

// index.js
// 省略以前文件 只展現須要實現的接口

// 定義 獲取指定用戶詳情 的接口
app.get('/users/:id', (req, res) => {
   // 首先咱們讀取已存在的用戶
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       const user = data["user" + req.params.id] 
       console.log( user );
       res.end( JSON.stringify(user));
   });
})

5. 刪除指定用戶

這一步咱們會建立 RESTful API 中的 /users,使用 DELETE 來刪除指定用戶

// index.js
// 省略以前文件 只展現須要實現的接口

// mock 一條要刪除的用戶id
const id = 2;

app.delete('/users', (req, res) => {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       delete data["user" + id];
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

4、REST 最佳實踐

1. URL 設計

1.1 "動詞 + 賓語"的操做指令結構

客戶端發出的數據操做指令都是"動詞 + 賓語"的結構。

如上面提到的,GET /user 這個命令,GET 是動詞,/user 是賓語。根據 HTTP 規範,動詞一概大寫。

動詞一般有如下五種 HTTP 方法:

GET:讀取(Read)
POST:新建(Create)
PUT:更新(Update)
PATCH:更新(Update),一般是部分更新
DELETE:刪除(Delete)

1.2 賓語必須是名詞

賓語就是 API 的 URL,是 HTTP 動詞做用的對象。它應該是名詞,不能是動詞。

好比,/users 是正確的,由於 URL 是名詞,而下面就都是錯誤的了:

/getUsers
/createUsers
/deleteUsers

1.3 建議複數 URL

由於 URL 是名詞,沒有單複數的限制,可是仍是建議若是是一個集合,就使用複數形式。如 GET /users 來讀取全部用戶列表。

1.4 避免多級 URL

避免在多層級資源時,使用多級 URL。常見案例如獲取某位用戶的購買過的某一類商品:

GET /users/100/product/120

這種 URL 語意不明,也不利拓展,建議只有第一級,其餘級別用查詢字符串來表達:

GET /users/100?product=120

2. 準確的狀態碼錶示

HTTP 五大類狀態碼有100多種,每一種狀態碼都有標準的(或者約定的)解釋,客戶端只需查看狀態碼,就能夠判斷出發生了什麼狀況,因此服務器應該返回儘量精確的狀態碼。

這邊列舉幾個常用的狀態碼介紹:

  • 303 See Other:表示參考另外一個 URL。
  • 400 Bad Request:服務器不理解客戶端的請求,未作任何處理。
  • 401 Unauthorized:用戶未提供身份驗證憑據,或者沒有經過身份驗證。
  • 403 Forbidden:用戶經過了身份驗證,可是不具備訪問資源所需的權限。
  • 404 Not Found:所請求的資源不存在,或不可用。
  • 405 Method Not Allowed:用戶已經經過身份驗證,可是所用的 HTTP 方法不在他的權限以內。
  • 410 Gone:所請求的資源已從這個地址轉移,再也不可用。
  • 415 Unsupported Media Type:客戶端要求的返回格式不支持。好比,API 只能返回 JSON 格式,可是客戶端要求返回 XML 格式。
  • 422 Unprocessable Entity:客戶端上傳的附件沒法處理,致使請求失敗。
  • 429 Too Many Requests:客戶端的請求次數超過限額。
  • 500 Internal Server Error:客戶端請求有效,服務器處理時發生了意外。
  • 503 Service Unavailable:服務器沒法處理請求,通常用於網站維護狀態。

3. 服務端響應

3.1 應該返回 JSON 對象

API 返回的數據格式應該是 JSON 一個對象。

3.2 發生錯誤時,不要返回 200 狀態碼

在發生錯誤時,若是還返回 200 狀態碼,前端須要解析返回數據才知道錯誤信息,這樣實際上取消了狀態碼,是不恰當的。

正確的作法應該是在錯誤時,返回對應錯誤狀態碼,並將錯誤信息返回:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}

參考資料

  1. 《維基百科 - 表現層狀態轉換》
  2. 《RESTful風格的springMVC》
  3. 《Node.js RESTful API》
  4. 《RESTful API 最佳實踐》

關於我

本文首發在 pingan8787我的博客,如需轉載請聯繫本人。
Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787...
ES小冊 js.pingan8787.com

微信公衆號

bg

相關文章
相關標籤/搜索