HTTP JSON API設計規范


前言

越來越多的Web應用程序使用JSON作為API的一種數據交換格式進行交互。本文檔的目標是使HTTP JSON API的設計風格保持一致,容易被理解和維護。一個優秀的API,應該是在其生命周期內能夠持續提供穩定、易用、受信任的服務,並且在API的生命周期結束時能讓其平滑的消亡。

注:RESTful API是目前比較成熟的一套Web應用程序的API設計理論,本文不對RESTful API過多介紹。在實際快速增長和多變的業務應用中,采用RESTful API需要更高的成本和對后端開發人員有更高的要求,我們更多采用這種輕量化的HTTP JSON API的設計。

約定

在本文檔中,使用的關鍵字會以中文+中括號包含的關鍵字英文表示:必須[MUST]。關鍵字”MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”按照RFC 2119中的描述進行解釋。

JSON數據類型

JSON(JavaScript Object Notation)是一種輕量級,基於文本,語言無關的數據交換格式。其包括了4種基本數據類型和2種結構數據類型,共6種數據類型。

基本數據類型

  • String 表示一個字符串。
  • Number 可以表示整數和浮點數。
  • Boolean 可以表示真假,值為true或false。
  • Null 通常用於表示空對象。

“true”和true,這兩個數據代表的是不同的數據類型。非字符串類型數據輸出時一定不要[MUST NOT]為兩端加上雙引號,否則可能產生不希望的后果(如if中判斷”false”的結果是true)。其他容易產生錯誤的例子如:0和”0″等。

結構數據類型

  • Object(對象)是無序的集合,以鍵值對的方式保持數據。一個Object中包含零到多個name/value的數據,數據間以逗號(,)分隔。name為String類型,value可以是任意類型的數據。Object的最后一個元素之后一定不要[MUST NOT]加上分隔符的逗號,否則可能導致解析出錯。
  • Array(數組)為多個值的有序集合,數組元素間以逗號(,)分隔。

協議

使用HTTP或HTTPS協議。

URL規范

URL代表所提供的API的唯一性和永久性,在此之前我們應該[SHOULD]設計合理的URL:

必須[MUST]全部使用小寫字母拼寫URL

// good
http://www.example.com/api/v1/users?orderby=name

// bad
http://www.example.com/API/V1/users?orderBy=name

必須[MUST]使用破折號 –

// good
http://www.example.com/api/v1/user-info

// bad
http://www.example.com/api/v1/user_info

破壞性行為(create,delete,update)必須[MUST]使用POST方法

// good
POST http://www.example.com/api/v1/user/delete

// bad
GET http://www.example.com/api/v1/user/detete?id=123

建議[RECOMMENDED]使用容易理解的英文單詞

// good
POST http://www.example.com/api/v1/user/list

// bad
GET http://www.example.com/api/v1/user/operate

HTTP響應頭

status

http響應的status必須(MUST)為200。通常JSON數據被用於通過XMLHttpRequest對象訪問,通過javascript進行處理。返回錯誤的狀態碼可能導致錯誤不被響應,數據不被處理。

參考:List_of_HTTP_status_codes

Content-Type

Content-Type字段定義了響應體的類型。一般情況下,瀏覽器會根據該類型對內容進行正確的處理。對於傳輸JSON數據的響應,Content-Type推薦(RECOMMENDED)設置為”text/javascript”或”text/plain”。 避免(MUST NOT)將Context-Type設置為text/html,否則可能導致安全問題。

Content-Type中可以指定字符集。通常 需要(SHOULD)明確指定一個字符集。如果是通過XMLHTTPRequest請求的數據,並且字符編碼為UTF-8時,可以不指定字符集。

Content-Type 示例

text/javascript;charset=UTF-8

HTTP響應體

返回的數據包含在HTTP響應體中。數據必須[MUST]是一個JSON Object。該Object可能[SHOULD]包含3個字段:code,msg,data。

{
    code: 200,
    msg: 'success',
    data: {
        xxx: '123'
    }
}

code

code 字段被設計為業務自定義的狀態碼, 必須(MUST)是一個不小於0的JSON Number整數,表示請求的狀態。這個字段 不可以(SHOULD NOT)被省略。

是否要在API里面自定義業務狀態碼,非常具有爭議,因為Http請求本身已經有了完備的狀態碼,再定義一套狀態碼直觀上感受多此一舉,但在實際開發中,可能由於用戶未登錄、登錄過期而有不同的返回結果和處理方式,所以必須[MUST]存在code字段。

狀態碼的定義也最好有一套規范,如按照用戶相關、授權相關、各種業務,做簡單的分類:

// 授權相關
1001: 無權限訪問
1002: access_token過期
1003: unique_token無效
...

// 用戶相關
2001: 未登錄
2002: 用戶信息錯誤
2003: 用戶不存在

// 業務1
3001: 業務1XXX
3002: 業務1XXX

// ...

msg

msg字段通常[SHOULD]是一個JSON String或JSON Object,表示除了請求狀態外服務端想要對本次請求做出的說明,使客戶端能夠獲取更多信息進行后續處理。這個字段是可選的[OPTIONAL] 。下面的兩個例子中,msg字段的信息都可以用於客戶端程序的后續處理,但是粒度和處理方式會有不同。

簡單說明的msg:

{
    "code": 1,
    "msg": "參數錯誤"
}

具有更多信息的msg:

{
    "code": 1,
    "msg": {
        "text": "參數錯誤",
        "parameters": {
            "ticket": "ticket參數無效"
        }
    }
}

data

data字段可以是任意JSON類型,表示請求返回的數據主體。這個字段是可選的[OPTIONAL]。數據主體data包含了在請求成功時有意義的數據。

一個查詢姓名請求的返回數據:

{
    "code": 200,
    "data": "John"
}

一個查詢用戶信息請求的返回數據:

{
    "code": 200,
    "data": {
        "username": "John",
        "age": "31",
        "gender": "male"
    }
}

一個查詢用戶列表信息請求的返回數據:

{
    "code": 200,
    "data": [
        {
            "username": "John",
            "age": "31",
            "gender": "male"
        },
        {
            "username": "Lily",
            "age": "28",
            "gender": "female"
        }
    ]
}

數據場景

本章為常見數據場景定義了通用的標准數據格式,用於數據傳輸和使用。

變通數據格式必須[MUST]是一個JSON Object,其中必須[MUST]包含e-type屬性和data屬性。e-type屬性標識數據類型,便於對數據進行解析;data屬性包含變通后的數據。變通數據可以[MAY]包含其他的屬性,標識數據的其他擴展信息。

變通數據格式的e-type屬性定義了table值。e-type屬性可以使用者擴展其他屬性值,擴展的屬性值必須[MUST]以“項目縮寫-名稱”命名,如“fc-list”,自主解析。

日期類型

日期類型不屬於JSON數據類型。對於日期類型,我們必須[MUST]使用JSON String來表示。為了讓日期能夠更容易的被顯示和被解析,對於日期我們應當[SHOULD)]使用更適合Internet的格式,遵循RFC 3339

日期展示格式

用來將日期展示給前端或者前端回傳給后端的格式:


// 一般日期格式
2018-12-6 11:21:08

// 時間戳格式(十位秒級)
1544066565


// 示例
{
  code: 0,
  msg: 'success',
  data: '2018-12-6 11:21:08'
}

記錄項

記錄項代表二維表中的一行,通常用於表示某個具體事務抽象的屬性。標准記錄項數據必須[MUST]為一個JSON Object,記錄項的主鍵命名必須[MUST]為“id”。

標准記錄項

{
  code: 0,
  msg: 'success',
  data: {
    "id": 1,
    "name": "John",
    "sex": "male",
    "age": 31
  }
}

變通記錄項

{
  code: 0,
  msg: 'success',
  data: [
    {
      label: '記錄ID',
      value: 1,
      type: 'number'
    },
    {
      label: '用戶名稱',
      value: 'John',
      type: 'string'
    },
    {
      label: '用戶性別',
      value: 'male',
    },
    {
      lable: '用戶年齡',
      value: 31
    }
  ]
}

二維表

二維表類型表識為table,是關系模型的主要數據結構。二維表結構具有變通數據格式。標准二維表數據必須[MUST]以一維JSON Array形式表示,JSON Array中每一項是一個JSON Object,代表一條記錄。JSON Object的每個成員代表一個字段。每條記錄的主鍵命名必須[MUST]為”id”。

在標准二維表中,字段名在每條記錄中都被傳輸,會造成額外的數據量傳輸。這個問題會隨着記錄數的增大會更加突出。為了減少傳輸數據量,變通格式使用二維JSON Array傳輸數據,擴展fields屬性用於字段說明。fields字段為JSON Array。

標准二維表

{
  code: 0,
  msg: 'success',
  data: [
    {
        "id": 1,
        "name": "John",
        "sex": "male",
        "age": 31
    },
    {
        "id": 2,
        "name": "Lily",
        "sex": "female",
        "age": 28
    }
  ]
}

變通二維表

{
  code: 0,
  msg: 'success',
  data: {
    "e-type": "table",
    "fields": ["id", "name", "sex", "age"],
    "data": [
        [1, "John", "male", 31],
        [2, "Lily", "female", 28]
    ]
  }
}

鍵值對

在一個JSON Object中表示鍵/值對:

  • 鍵的屬性名必須[MUST]為name, 杜絕[MUST NOT]使用key或k
  • 值的屬性名必須[MUST]為value, 杜絕[MUST NOT]使用v。
  • 可以[MAY]為其擴展屬性名label,一般同name值相同。

簡單鍵/值

{
  code: 0,
  msg: 'success',
  data: {
    "name": "John",
    "value": 1,
    "lable": "John" // 可選
  }
}

有序集合

鍵/值有序集合表示對事務或邏輯類型的抽象與分類。常見的應用場景有單選復選框集合,下拉菜單等。

標准的鍵/值有序集合是一個JSON Array,集合中的每一項是一個JSON Object。項 必須[MUST] 包含name和value屬性。 可以[MAY] 通過其他的屬性修飾每一項的特殊信息,如selected。

{
  code: 0,
  msg: 'success',
  data: [
    {
        "name": "不滿意",
        "value": 0,
        "selected": true
    },
    {
        "name": "滿意",
        "value": 1
    },
    {
        "name": "非常滿意",
        "value": 2,
        "selected": true
    }
  ]
}

數據頁

數據頁是列表數據常用的數據方式,可能通過查詢或翻頁獲得數據。數據頁是二維表數據的包裝,包含列表數據本身更多的信息。

數據頁必須[MUST]是一個JSON Object,其中必須[MUST]包含的屬性為data。data是一個二維表。數據頁可以包括一些可選[OPTIONAL]的屬性,表示當前數據頁的信息。下表列舉了數據頁的可選屬性。

參數/屬性

  • pageNumber{Number} – 當前頁碼,計數必須[MUST]為不小於1的整數,從1開始。通常簡寫為:pn
  • pageSize{Number} – 每頁顯示條數, 必須[MUST]大於0。通常簡寫為:ps
  • total{Number} – 列表總記錄數, 必須[MUST]為不小於0的整數。表示當前條件下所有記錄的數目,非本頁的記錄數。
  • keyword{String} – 列表所屬的搜索關鍵字。
  • orderBy{String} – 列表排序規則。多個排序規則之間以逗號分割(,);正序或倒序以asc或desc表示,與字段名之間以一個空格間隔。例:”id desc,name asc”
  • condition{Object} – 列表所屬的搜索條件集合。屬性中可以包含或不包含keyword字段,如果不包含,建議(RECOMMMANDED)在解析的時候附加搜索關鍵字keyword條件。
  • startTime{Datetime} – 開始時間,用來搜索帶有創建時間的列表數據,一般跟endTime成對出現
  • endTime{Datetime} – 結束時間,同上

數據頁示例

{
  code: 0,
  msg: 'success',
  data: {
    "pn": 1,
    "ps": 10,
    "total": 100,
    "keyword": "John",
    "orderBy": "id desc, name asc",
    "condition": {},
    "startTime": "2010-11-11 11:11:11",
    "endTime": "2018-11-11 11:11:11",
    "data": [
        {
            "id": 1,
            "name": "John",
            "sex": "male",
            "age": 31
        },
        {
            "id": 2,
            "name": "Lily",
            "sex": "female",
            "age": 28
        }
    ]
  }
}

樹結構

樹形數據用於表示層疊的數據結構。樹型數據必須[MUST]是一個JSON Object,代表樹型數據的根節點。下面是標准定義的可選節點列表,不在列表中的屬性可以[SHOULD]自行擴展。

節點屬性

  • id {Number|String} – 節點的唯一標識。
  • text {String}- 名稱或用於顯示的字符串。
  • children {Array} – 子節點列表。

數據示例

// good
{
  code: 0,
  msg: 'success',
  data: {
    "id": 1,
    "text": "中國",
    "children": [
        {
            "id": 10,
            "text": "北京",
            "children": [
                {
                    "id": 100,
                    "text": "東城區"
                },
                {
                    "id": 101,
                    "text": "西城區"
                },
                {
                    "id": 102,
                    "text": "海淀區"
                }
            ]
        },
        {
            "id": 31,
            "text": "海南",
            "children": [
                {
                    "id": 600,
                    "text": "海口"
                },
                {
                    "id": 601,
                    "text": "三亞"
                },
                {
                    "id": 602,
                    "text": "五指山"
                }
            ]
        }
    ]
  }
}


//bad
{
  code: 0,
  msg: 'success',
  data: [
    {
        "id": 1,
        "text": "中國",
        "parentId": 0,
    },
    {
        "id": 2,
        "text": "北京",
        "parentId": 1,
    },
    {
        "id": 3,
        "text": "東城區",
        "parentId": 2,
    },
    {
        "id": 4,
        "text": "西城區",
        "parentId": 2,
    }
  ]
}

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM