先後端徹底分離之 API 設計

背景

API 就是開發者使用的界面。個人目標不只是能用,並且好用,跨平臺(PC, Android, IOS, etc...)使用。本文將詳細介紹 API 的設計及異常處理,並將異常信息進行封裝友好地反饋給前端.前端

上篇文章 先後端徹底分離初探 只是講了些寬泛的概念,接下來的文章將直接上乾貨,乾貨的源碼會掛在 GitHub 上。git

先後端徹底分離後,前端和後端如何交互?答:經過雙方協商好的API。github

接下來我分享我本身設計的 API 接口,歡迎各位朋友指教。json

API 設計理念

  1. 將涉及的實體抽象成資源,即按 id 訪問資源,在 url 上作文章,之後不再用爲 url 起名字而苦惱了;segmentfault

  2. 使用 HTTP 動詞對資源進行 CRUD(增刪改查):後端

    get -> 查, post -> 增, put -> 改, delete -> 刪
  3. URL 命名規則,對於資源沒法使用一個單數名詞表示的狀況,我使用中橫線 - 鏈接api

    • 資源採用名詞命名,e.g:產品 -> product安全

    • 新增資源,e.g:新增產品 url -> /product, verb -> POST分佈式

    • 修改資源,e.g:修改產品 url -> /products/{id}, verb -> PUT模塊化

    • 資源詳情,e.g:指定產品詳情 url -> /products/{id}, verb -> GET

    • 刪除資源,e.g:刪除產品 url -> /products/{id}, verb -> DELETE

    • 資源列表,e.g:產品列表 url -> /products, verb -> GET

    • 資源關聯關係,e.g:收藏產品 url -> /products/{id}/star, verb -> PUT

    • 資源關聯關係,e.g:刪除收藏產品 url -> /products/{id}/star, verb -> DELETE

目前我 API 的設計只涉及這兩點,至於第三點 HATEOAS(Hypermedia As The Engine Of Application State) 那就由讀者本身去選擇了,

<!--more-->

項目地址

本文中只涉及了設計的理念,具體的實現請下載源碼 rest-api,項目內寫了比較詳細的註釋。

項目實戰

實戰將從業務場景出發,詳細介紹如何使用 HTTP verb 對資源進行操做(狀態轉移),使用 JSON 返回結果(資源表述),並定義 JSON 的基礎結構。

JSON 結構

requestParams:

{
}

responseBody:

{
  "meta": {
  },
  "data": {
  }
}

meta 中封裝操做成功或失敗的消息,data 中封裝返回的具體數據。

當新建商品或更新產品時,相關屬性封裝在 JSON 中,經過 POST 或 PUT 發送。

{
  "name": "Apple Watch SPORT",
  "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
}

當用戶對商品進行操做後,將獲得響應結果。GET, POST, PUT 操做成功,返回以下結果

{
  "meta": {
    "code": 201,
    "message": "建立成功"
  },
  "data": {
    "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
    "name": "Apple Watch SPORT",
    "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
  }
}

DELETE 操做成功,返回以下結果

{
  "meta": {
    "code": 204,
    "message": "刪除成功"
  }
}

業務場景一

電商網站的管理員對商品進行新增、編輯、刪除、瀏覽的操做,暫時不考慮認證受權,只關注對商品的操做。

爲了之後便於作分佈式,全部資源 id(表主鍵)均採用 uuid。

新增商品
  1. url: /api/product

  2. method: POST

  3. requestParams:

    {
      "name": "Apple Watch SPORT",
      "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
    }
  4. responseBody

    {
      "meta": {
        "code": 201,
        "message": "建立成功"
      },
      "data": {
        "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
        "name": "Apple Watch SPORT",
        "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
      }
    }
編輯商品
  1. url: /api/products/{id}

  2. method: PUT

  3. requestParams:

    {
      "name": "iPhone 6",
      "description": "這次蘋果發佈會發佈了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計再也不棱角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。"
    }
  4. responseBody

    {
      "meta": {
        "code": 200,
        "message": "修改爲功"
      },
      "data": {
        "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
        "name": "iPhone 6",
        "description": "這次蘋果發佈會發佈了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計再也不棱角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。"
      }
    }
刪除商品
  1. url: /api/products/{id}

  2. method: DELETE

  3. responseBody

    {
      "meta": {
        "code": 204,
        "message": "刪除成功"
      },
      "data": {}
    }
獲取商品詳情
  1. url: /api/products/{id}

  2. method: GET

  3. responseBody:

    //刪除前
    
    {
      "meta": {
        "code": 200,
        "message": "查詢成功"
      },
      "data": {
        "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
        "name": "Apple Watch SPORT",
        "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
      }
    }
    //刪除後
    {
      "meta": {
        "code": 404,
        "message": "指定產品不存在"
      }
    }
獲取商品列表(未分頁)
  1. url: /api/products

  2. method: GET

  3. responseBody

    {
      "meta": {
        "code": 200,
        "message": "獲取所有商品成功"
      },
      "data": [
        {
          "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
          "name": "Apple Watch SPORT",
          "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
        },
        {
          "id": "9db1992a-c342-4ff0-a2a4-aeb3dbfd93f6",
          "name": "Apple Watch SPORT",
          "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
        },
        {
          "id": "4481619b-45c5-4729-9539-f93bb01f10d8",
          "name": "Apple Watch SPORT",
          "description": "Sport 系列的錶殼材料爲輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質爲顯示屏提供保護。搭配高性能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。"
        }
      ]
    }

業務場景二

業務場景一中只涉及了單個資源的操做,但實際場景中還有些關聯操做;如用戶去電商網站瀏覽商品,並收藏了一些商品,以後又取消收藏了部分商品。

暫時不考慮用戶認證受權,之後加了token後,用戶信息能夠從中獲取。

收藏商品
  1. url: /api/products/{id}/star

  2. method: PUT

  3. responseBody

    {
      "meta": {
        "code": 200,
        "message": "收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功"
      },
      "data": [
        {
          "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
          "name": "iPhone 6",
          "description": "這次蘋果發佈會發佈了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計再也不棱角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。"
        }
      ]
    }
取消收藏商品
  1. url: /api/products/{id}/star

  2. method: DELETE

  3. responseBody

    {
      "meta": {
        "code": 200,
        "message": "刪除收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功"
      },
      "data": []
    }

自定義異常和異常處理

全部自定義異常繼承 RuntimeException,在業務層拋出,統一在 Controller 層進行處理。

異常分爲全局異常和局部異常,例如 http method unsupported (405),unauthorized (401),accessDenied (403),not found (404) 等屬於全局異常。針對對獨立業務的一些異常屬於局部異常,例如產品編輯出錯。

異常在 Controller 中進行處理,並封裝成 json 返回給前端,封裝後的數據以下,相關實現見源碼

{
  "meta": {
    "code": 404,
    "message": "指定產品不存在"
  }
}
{
  "meta": {
    "code": 405,
    "message": "Request method 'POST' not supported"
  }
}

項目運行截圖部分

本系列文章

  • 先後端徹底分離初探

  • 先後端徹底分離之API設計

  • 先後端徹底分離之安全認證與受權-上

  • 先後端徹底分離之安全認證與受權-下

  • 先後端徹底分離以前端模塊化開發

  • 先後端徹底分離以前端路由系統

  • 先後端徹底分離以後端面向服務的模塊化開發

原文出自 先後端徹底分離之API設計,歡迎轉載,轉載請註明出處。

相關文章
相關標籤/搜索