最新規格 (v1.1)

狀態

此頁面呈現 JSON:API 最新發布的版本,目前為 1.1 版。JSON:API 的新版本將**永遠保持向下相容性**,採用「**只新增,不移除**」的策略。您可以在我們的討論區提出新增功能的建議。

如果您在規格說明文字中發現錯誤,或者您撰寫了實作,請在我們的 GitHub 儲存庫 開啟 issue 或 pull request 告知我們。

簡介

JSON:API 是一個規範,用於規範客戶端應如何請求提取或修改資源,以及伺服器應如何回應這些請求。JSON:API 可以透過 擴充功能設定檔 輕鬆擴充。

JSON:API 的設計旨在最大限度地減少客戶端和伺服器之間的請求次數和傳輸的資料量。這種效率的提升並不會犧牲可讀性、彈性和可發現性。

JSON:API 要求使用 JSON:API 媒體類型 (application/vnd.api+json) 來交換資料。

語義

本規格定義的所有文件成員、查詢參數和處理規則統稱為「規格語義」。

某些文件成員、查詢參數和處理規則保留給實作者自行定義。這些稱為「實作語義」。

所有其他語義均保留供本規格未來可能使用。

約定

本文檔中的關鍵字「必須 (MUST)」、「不得 (MUST NOT)」、「必要 (REQUIRED)」、「應 (SHALL)」、「不應 (SHALL NOT)」、「應該 (SHOULD)」、「不應該 (SHOULD NOT)」、「建議 (RECOMMENDED)」、「不建議 (NOT RECOMMENDED)」、「可以 (MAY)」和「可選 (OPTIONAL)」的解釋應遵循 BCP 14 [RFC2119] [RFC8174] 中的描述,且僅限於以全部大寫字母顯示時,如本文所示。

JSON:API 媒體類型

JSON:API 媒體類型為 application/vnd.api+json

媒體類型參數

JSON:API 規格支援兩個媒體類型參數:extprofile,分別用於指定 擴充功能設定檔

備註:媒體類型參數是伴隨媒體類型的額外資訊。例如,在標頭 Content-Type: text/html;charset="utf-8" 中,媒體類型為 text/html,而 charset 是一個參數。

擴充功能

擴充功能提供了一種透過定義額外的 規格語義 來「擴充」基本規格的方法。

擴充功能不能更改或移除規格語義,也不能指定實作語義。

設定檔

設定檔提供了一種在不同實作之間共享特定規格使用方法的方法。

設定檔可以指定 實作語義,但不能更改、新增或移除規格語義。

媒體類型參數規則

JSON:API 媒體類型**不得**指定 extprofile 以外的任何媒體類型參數。ext 參數用於支援 擴充功能profile 參數用於支援 設定檔

擴充功能和設定檔均由 URI 唯一識別。 瀏覽擴充功能或設定檔的 URI **應該**會返回描述其使用方法的文件。 extprofile 參數的值**必須**分別等於以空格 (U+0020 空格,「 」) 分隔的擴充功能或設定檔 URI 列表。

備註:序列化 extprofile 媒體類型參數時,HTTP 規格要求參數值必須用引號 (U+0022 引號,「"」) 括起來。

擴充功能規則

擴充功能**可以**施加額外的處理規則或進一步的限制,並且**可以**如下所述定義新的物件成員。

擴充功能**不得**減少或移除本規格或其他擴充功能定義的任何處理規則、限制或物件成員需求。

擴充功能**可以**在本規格定義的文件結構中定義新的成員。擴充功能成員名稱的規則涵蓋在下方

擴充功能**可以**定義新的查詢參數。擴充功能定義的查詢參數的規則涵蓋在下方

當擴充功能定義新的查詢參數或文件成員時,擴充功能**必須**定義一個命名空間,以確保擴充功能永遠不會與本規格的當前或未來版本衝突。命名空間**必須**符合以下所有條件

  • 命名空間**必須**包含至少一個字元。
  • 命名空間**必須**僅包含以下字元
    • U+0061 到 U+007A,「a-z」
    • U+0041 到 U+005A,「A-Z」
    • U+0030 到 U+0039,「0-9」

擴充功能**不得**定義多個命名空間。對於任何給定的擴充功能,所有查詢參數和文件成員使用的命名空間**必須**相同。

在以下範例中,命名空間為 version 的擴充功能指定了一個資源物件成員 version:id 以支援每個資源的版本控制。此成員可能如下所示

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json;ext="https://jsonapi.dev.org.tw/ext/version"

// ...
{
  "type": "articles",
  "id": "1",
  "version:id": "42",
  "attributes": {
    "title": "Rails is Omakase"
  }
}
// ...

設定檔規則

設定檔的使用規則由 RFC 6906 規定。

設定檔**可以**定義保留給實作者的文件成員和處理規則。

設定檔**不得**定義任何查詢參數,但實作特定的查詢參數除外。

設定檔**不得**更改或移除本規格或擴充功能定義的處理規則。但是,設定檔**可以**定義查詢參數的處理規則,其處理規則已保留供實作者自行定義。

例如,設定檔可以定義解釋filter 查詢參數的規則,但它不能指定include 查詢參數中的關係名稱是以空格分隔而不是以點分隔。

與擴充功能不同,設定檔不需要為文件成員定義命名空間,因為設定檔不能定義規格語義,因此不會與本規格的當前或未來版本衝突。但是,設定檔可能會與其他設定檔衝突。因此,實作者有責任確保他們不支援衝突的設定檔。

在以下範例中,設定檔定義了一個 timestamps 屬性。根據設定檔,該屬性必須是一個包含 created 成員和 modified 成員的物件,並且這些成員的值必須使用 RFC 3339 格式。套用此設定檔後,回應可能如下所示

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json;profile="https://example.com/resource-timestamps"

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase",
    "timestamps": {
      "created": "2020-07-21T12:09:00Z",
      "modified": "2020-07-30T10:19:01Z"
    }
  }
}
// ...

內容協商

通用職責

客戶端和伺服器**必須**在 Content-Type 標頭中使用 JSON:API 媒體類型發送所有 JSON:API 負載。

當客戶端和伺服器已將一個或多個擴充功能套用至 JSON:API 文件時,它們**必須**在 Content-Type 標頭中指定 ext 媒體類型參數。

當客戶端和伺服器已將一個或多個設定檔套用至 JSON:API 文件時,它們**必須**在 Content-Type 標頭中指定 profile 媒體類型參數。

客戶端職責

處理 JSON:API 回應文件時,客戶端**必須**忽略伺服器 Content-Type 標頭中除 extprofile 參數以外的任何參數。

客戶端**可以**在 Accept 標頭中使用 ext 媒體類型參數,以要求伺服器將所有指定的擴充功能套用至回應文件。

客戶端**可以**在 Accept 標頭中使用 profile 媒體類型參數,以請求伺服器將一個或多個設定檔套用至回應文件。

備註:客戶端允許在 Accept 標頭中發送多個可接受的媒體類型,包括 JSON:API 媒體類型的多個執行個體。這允許客戶端請求 extprofile 媒體類型參數的不同組合。客戶端可以使用 品質值 來表示某些組合不如其他組合。未指定品質值的媒體類型彼此同等優先,不論其順序為何,並且始終被認為比品質值小於 1 的媒體類型更優先。

伺服器職責

如果請求在 Content-Type 標頭中指定了 JSON:API 媒體類型,並且該媒體類型包含除 extprofile 以外的任何媒體類型參數,則伺服器**必須**以 415 不支援的媒體類型 狀態碼回應。

如果請求在 `Content-Type` 標頭中指定了 JSON:API 媒體類型,且該媒體類型被 `ext` 媒體類型參數修改,並且該參數包含不被支援的擴展 URI,則伺服器 **必須** 回應 `415 Unsupported Media Type` 狀態碼。

注意:如果不支援此規範 1.1 版本的 JSON:API 伺服器,如果存在 `ext` 或 `profile` 媒體類型參數,則會以 `415 Unsupported Media Type` 用戶端錯誤回應。

如果請求的 `Accept` 標頭包含 JSON:API 媒體類型,伺服器 **必須** 忽略被 `ext` 或 `profile` 以外的媒體類型參數修改的該媒體類型實例。如果該媒體類型的所有實例都被 `ext` 或 `profile` 以外的媒體類型參數修改,則伺服器 **必須** 回應 `406 Not Acceptable` 狀態碼。如果該媒體類型的每個實例都被 `ext` 參數修改,並且每個都包含至少一個不被支援的擴展 URI,則伺服器 **也必須** 回應 `406 Not Acceptable`。

如果收到 `profile` 參數,伺服器 **應該** 嘗試將任何請求的設定檔應用於其回應。伺服器 **必須** 忽略它無法辨識的任何設定檔。

注意:上述規則保證了用戶端和伺服器之間對擴展的嚴格一致性,而設定檔的應用則由伺服器自行決定。

支援 `ext` 或 `profile` 媒體類型參數的伺服器 **應該** 指定 `Vary` 標頭,並將 `Accept` 作為其值之一。這適用於應用和未應用任何設定檔擴展的回應。

注意:某些 HTTP 中介軟體(例如 CDN)可能會忽略 `Vary` 標頭,除非特別設定為遵循它。

文件結構

本節描述 JSON:API 文件的結構,該結構由JSON:API 媒體類型識別。JSON:API 文件以 JavaScript 物件表示法 (JSON) [RFC8259] 定義。

儘管請求和回應文件使用相同的媒體類型,但某些方面僅適用於其中之一。這些差異將在下方說明。

擴展 **可以** 在文件結構中定義新的成員。這些成員 **必須** 符合下方指定的命名要求。

除非另有說明,否則此規範或任何應用擴展定義的物件 **不得** 包含任何其他成員。用戶端和伺服器實作 **必須** 忽略不符合規範的成員。

注意:這些條件允許此規範透過添加變更來發展。

頂層

每個包含資料的 JSON:API 請求和回應文件的根目錄 **必須** 是一個 JSON 物件。此物件定義了文件的「頂層」。

文件 **必須** 包含以下至少一個頂層成員

  • `data`:文件的「主要資料」。
  • `errors`:錯誤物件的陣列。
  • `meta`:包含非標準中繼資訊的中繼物件
  • 由應用擴展定義的成員。

成員 `data` 和 `errors` **不得** 同時存在於同一個文件中。

文件 **可以** 包含以下任何頂層成員

  • `jsonapi`:描述伺服器實作的物件。
  • `links`:與整個文件相關的連結物件
  • `included`:與主要資料和/或彼此相關的資源物件陣列(「包含的資源」)。

如果文件不包含頂層 `data` 鍵,則 `included` 成員 **也一定不能** 存在。

頂層連結物件 **可以** 包含以下成員

  • `self`:產生目前回應文件的連結。如果文件已應用擴展或設定檔,則此連結 **應該** 由連結物件表示,其中 `type` 目標屬性指定具有所有適用參數的 JSON:API 媒體類型。
  • `related`:當主要資料表示資源關係時的相關資源連結
  • `describedby`:指向目前文件的描述文件(例如 OpenAPI 或 JSON Schema)的連結
  • 主要資料的分頁連結。

注意:頂層 `links` 物件中的 `self` 連結允許用戶端重新整理目前回應文件所表示的資料。用戶端應該能夠使用提供的連結,而無需應用任何額外資訊。因此,連結必須包含用戶端為產生回應文件所提供的查詢參數。這包括但不限於用於[包含相關資源][fetching resources]、[稀疏欄位集][fetching sparse fieldsets]、[排序][fetching sorting]、[分頁][fetching pagination] 和 [篩選][fetching filtering] 的查詢參數。

文件的「主要資料」是請求所針對的資源或資源集合的表示。

主要資料 **必須** 是以下其中之一

例如,以下主要資料是單個資源物件

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      // ... this article's attributes
    },
    "relationships": {
      // ... this article's relationships
    }
  }
}

以下主要資料是參照相同資源的單個資源識別碼物件

{
  "data": {
    "type": "articles",
    "id": "1"
  }
}

邏輯資源集合 **必須** 表示為陣列,即使它只包含一個項目或為空。

資源物件

「資源物件」出現在 JSON:API 文件中以表示資源。

資源物件 **必須** 包含以下至少一個頂層成員

  • id
  • type

例外:當資源物件源自用戶端並且表示要在伺服器上建立的新資源時,不需要 `id` 成員。在這種情況下,用戶端 **可以** 包含 `lid` 成員,以在文件中**本地**按 `type` 唯一識別資源。

此外,資源物件 **可以** 包含以下任何頂層成員

  • `attributes`:表示資源某些資料的屬性物件
  • `relationships`:描述資源與其他 JSON:API 資源之間關係的關係物件
  • `links`:包含與資源相關連結的連結物件
  • `meta`:包含關於資源的非標準中繼資訊的中繼物件,這些資訊無法表示為屬性或關係。

以下是如何在文件中顯示文章(即類型為「文章」的資源)

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  }
}
// ...

識別

如上所述,每個資源物件 **必須** 包含 `type` 成員。每個資源物件 **也必須** 包含 `id` 成員,除非資源物件源自用戶端並且表示要在伺服器上建立的新資源。如果由於此例外而省略 `id`,則 **可以** 包含 `lid` 成員,以在文件中**本地**按 `type` 唯一識別資源。`lid` 成員的值對於文件中資源的每個表示形式 **必須** 相同,包括資源識別碼物件

`id`、`type` 和 `lid` 成員的值 **必須** 是字串。

在給定的 API 中,每個資源物件的 `type` 和 `id` 對 **必須** 識別單個唯一資源。(由伺服器或多個充當一個伺服器控制的 URI 集合構成一個 API。)

`type` 成員用於描述共享通用屬性和關係的資源物件

type 成員的值**必須**遵循與成員名稱相同的約束。

註:此規範與變形規則無關,因此 type 的值可以是複數或單數。但是,在整個實作中應一致地使用相同的值。

欄位

資源物件的屬性及其關聯統稱為其「欄位」。

資源物件的欄位**必須**彼此共享一個共同的命名空間,並與 typeid 共享。換句話說,資源不能具有同名的屬性和關聯,也不能具有名為 typeid 的屬性或關聯。

屬性

attributes 鍵的值**必須**是一個物件(「屬性物件」)。屬性物件的成員(「屬性」)表示在其定義的資源物件的相關資訊。

屬性可以包含任何有效的 JSON 值,包括涉及 JSON 物件和陣列的複雜資料結構。

引用相關資源的鍵(例如 author_id)**不應該**作為屬性出現。相反,**應該**使用關聯

註:有關此容器的更多限制,請參閱欄位成員名稱

關聯

relationships 鍵的值**必須**是一個物件(「關聯物件」)。關聯物件的每個成員表示從已定義的資源物件到其他資源物件的「關聯」。

關聯可以是一對一或一對多。

關聯的名稱由其鍵給出。該鍵的值**必須**是一個物件(「關聯物件」)。

「關聯物件」**必須**包含以下至少一項

  • links:包含以下至少一項的連結物件
    • self:關聯本身的連結(「關聯連結」)。此連結允許客戶端直接操作關聯。例如,透過article的關聯 URL 移除author 將斷開此人與article的連接,而不會刪除people資源本身。成功擷取後,此連結會傳回相關資源的連結作為其主要資料。(請參閱擷取關聯。)
    • related相關資源連結
    • 由應用擴展定義的成員。
  • data資源連結
  • meta:包含關於關聯的非標準中繼資訊的中繼物件
  • 由應用擴展定義的成員。

表示一對多關聯的關聯物件也**可以**在 links 成員下包含分頁連結,如下所述。關聯物件中的任何分頁連結**必須**對關聯資料進行分頁,而不是對相關資源進行分頁。

註:有關此容器的更多限制,請參閱欄位成員名稱

「相關資源連結」提供對關聯連結資源物件的存取。擷取後,相關資源物件會作為回應的主要資料傳回。

例如,articlecomments 關聯可以指定一個連結,當透過 GET 請求擷取時,該連結會傳回評論資源物件的集合。

如果存在,相關資源連結**必須**引用有效的 URL,即使關聯目前未與任何目標資源關聯。此外,相關資源連結**不得**因其關聯的內容更改而更改。

資源連結

複合文件中的資源連結允許客戶端將所有包含的資源物件連結在一起,而無需透過連結GET任何 URL。

資源連結**必須**表示為以下其中一項

註:雖然實作可能會這樣做,但規範並未賦予一對多關聯的連結陣列中資源識別碼物件的順序任何意義。資源識別碼物件的陣列可以表示有序或無序的關聯,並且兩種類型可以在一個回應物件中混合。

例如,以下文章與author關聯

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "http://example.com/articles/1/relationships/author",
        "related": "http://example.com/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...

author 關聯包含關聯本身的連結(允許客戶端直接更改相關作者)、用於擷取資源物件的相關資源連結以及連結資訊。

每個資源物件中可選的 links 成員包含與資源相關的連結

如果存在,此連結物件**可以**包含一個標識資源物件所表示資源的 self 連結

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...

伺服器**必須**使用包含資源作為主要資料的回應來回應對指定 URL 的 GET 請求。

資源識別碼物件

「資源識別碼物件」是用於識別單個資源的物件。

「資源識別碼物件」**必須**包含 type 成員。它也**必須**包含 id 成員,除非它表示要在伺服器上建立的新資源。在這種情況下,**必須**包含一個標識新資源的 lid 成員。

`id`、`type` 和 `lid` 成員的值 **必須** 是字串。

「資源識別碼物件」也**可以**包含 meta 成員,其值是一個包含非標準中繼資訊的中繼物件。

複合文件

伺服器**可以**允許包含相關資源以及請求的主要資源的回應。此類回應稱為「複合文件」。

在複合文件中,所有包含的資源**必須**在頂級 included 成員中表示為資源物件的陣列。

每個包含的資源物件**必須**透過源自文件主要資料的關聯鏈來識別。這表示複合文件需要「完整連結」,並且沒有與文件的主要資料直接或間接關聯的資源物件都不能包含在內。

完整連結要求的唯一例外是,由於客戶端請求的稀疏欄位集而排除原本包含連結資料的關聯欄位。

具有多個包含關聯的完整範例文件

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "links": {
      "self": "http://example.com/articles/1"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "firstName": "Dan",
      "lastName": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

複合文件**不得**為每個 typeid 對包含多個資源物件

註:在單個文件中,您可以將 typeid 視為唯一引用文件另一部分中的資源物件的複合鍵。

註:對於不包含 id 成員但包含 lid 的資源,lid 足以在整個文件中建立資源身分,從而在資源物件和資源識別碼物件之間建立連結。

註:這種方法可確保每個回應都傳回單個規範的資源物件,即使多次引用相同的資源也是如此。

中繼資訊

在指定的位置,可以使用 meta 成員來包含非標準的中繼資訊。每個 meta 成員的值**必須**是一個物件(「中繼物件」)。

meta 物件中**可以**指定任何成員。

例如

{
  "meta": {
    "copyright": "Copyright 2015 Example Corp.",
    "authors": [
      "Yehuda Katz",
      "Steve Klabnik",
      "Dan Gebhardt",
      "Tyler Kellen"
    ]
  },
  "data": {
    // ...
  }
}

在指定的位置,可以使用 links 成員來表示連結。此成員的值**必須**是一個物件(「連結物件」)。

在此物件中,連結**必須**表示為以下其中一項

**應該**從連結的名稱推斷連結的關聯類型,除非連結是連結物件且連結物件具有 rel 成員。

連結的上下文是它出現的頂級物件資源物件關聯物件

在以下範例中,self 連結是一個字串,而 related 連結是一個連結物件related 連結物件提供了關於目標相關資源集合的額外資訊,以及作為該集合描述文件的 schema。

"links": {
  "self": "http://example.com/articles/1/relationships/comments",
  "related": {
    "href": "http://example.com/articles/1/comments",
    "title": "Comments",
    "describedby": "http://example.com/schemas/article-comments",
    "meta": {
      "count": 10
    }
  }
}

「連結物件」是一個代表 網路連結 的物件。

連結物件**必須**包含以下成員:

  • href:一個字串,其值是一個指向連結目標的 URI 參考 [RFC3986 第 4.1 節]。

連結物件**可以**包含以下任何成員:

  • rel:一個表示連結關係類型的字串。該字串**必須**是 有效的連結關係類型
  • describedby:一個指向連結目標描述文件(例如 OpenAPI 或 JSON Schema)的 連結
  • title:一個字串,作為連結目的地的標籤,以便它可以用作人類可讀的識別符號(例如,選單項目)。
  • type:一個表示連結目標媒體類型的字串。
  • hreflang:一個字串或一個字串陣列,表示連結目標的語言。字串陣列表示連結目標以多種語言提供。每個字串**必須**是有效的語言標籤 [RFC5646]。
  • meta:一個包含關於連結的非標準中繼資訊的中繼物件。

注意:typehreflang 成員只是提示;當實際點擊連結時,不保證目標資源以指定的媒體類型或語言提供。

JSON:API 物件

JSON:API 文件**可以**在其頂層 jsonapi 成員下包含有關其實作的資訊。如果存在,jsonapi 成員的值**必須**是一個物件(一個「jsonapi 物件」)。

jsonapi 物件**可以**包含以下任何成員:

  • version - 其值是一個字串,表示支援的最高 JSON:API 版本。
  • ext - 所有已應用 擴充功能 的 URI 陣列。
  • profile - 所有已應用 設定檔 的 URI 陣列。
  • meta - 一個包含非標準中繼資訊的 中繼 物件。

客戶端和伺服器**不得**使用 extprofile 成員進行內容協商。內容協商**必須**僅基於 Content-Type 標頭中的媒體類型參數進行。

下面是一個簡單的例子:

{
  "jsonapi": {
    "version": "1.1",
    "ext": [
      "https://jsonapi.dev.org.tw/ext/atomic"
    ],
    "profile": [
      "http://example.com/profiles/flexible-pagination",
      "http://example.com/profiles/resource-versioning"
    ]
  }
}

如果 version 成員不存在,客戶端應假設伺服器至少實作了規範的 1.0 版本。

注意:由於 JSON:API 致力於僅進行增量更改,因此版本字串主要指示伺服器可能支援哪些新功能。

成員名稱

JSON:API 文件中使用的實作和設定檔定義的成員名稱**必須**由客戶端和伺服器區分大小寫,並且它們**必須**滿足以下所有條件:

  • 成員名稱**必須**包含至少一個字元。
  • 成員名稱**必須**僅包含下面列出的允許字元。
  • 成員名稱**必須**以「全局允許字元」開頭和結尾,如下所定義。

為了更容易地將成員名稱映射到 URL,**建議**成員名稱僅使用 RFC 3986 中指定的非保留 URL 安全字元。

允許的字元

以下「全局允許字元」**可以**在成員名稱中的任何位置使用:

  • U+0061 到 U+007A,「a-z」
  • U+0041 到 U+005A,「A-Z」
  • U+0030 到 U+0039,「0-9」
  • U+0080 及以上(非 ASCII Unicode 字元;*不建議使用,非 URL 安全*)

此外,除了第一個或最後一個字元外,成員名稱中允許使用以下字元:

  • U+002D 減號,「-」
  • U+005F 底線,「_」
  • U+0020 空格,「 」*(不建議使用,非 URL 安全)*

保留字元

以下字元**不得**在實作和 設定檔 定義的成員名稱中使用:

  • U+002B 加號,「+」*(在 URL 查詢字串中具有多重含義)*
  • U+002C 逗號,「,」*(用作關係路徑之間的分隔符號)*
  • U+002E 句點,「.」*(用作關係路徑中的分隔符號)*
  • U+005B 左方括號,「[」*(用於查詢參數系列)*
  • U+005D 右方括號,「]」*(用於查詢參數系列)*
  • U+0021 驚嘆號,「!」
  • U+0022 引號,「"」
  • U+0023 井號,「#」
  • U+0024 美元符號,「$」
  • U+0025 百分號,「%」
  • U+0026 符號,「&」
  • U+0027 撇號,「'」
  • U+0028 左括號,「(」
  • U+0029 右括號,「)」
  • U+002A 星號,「*」
  • U+002F 斜線,「/」
  • U+003A 冒號,「:」
  • U+003B 分號,「;」
  • U+003C 小於號,「<」
  • U+003D 等於號,「=」
  • U+003E 大於號,「>」
  • U+003F 問號,「?」
  • U+0040 商業 @,「@」(除了在 @-成員 中作為第一個字元之外)
  • U+005C 反斜線,「\」
  • U+005E 抑揚符,「^」
  • U+0060 重音符,「`」
  • U+007B 左大括號,「{」
  • U+007C 豎線,「|」
  • U+007D 右大括號,「}」
  • U+007E 波浪號,「~」
  • U+007F 刪除
  • U+0000 到 U+001F(C0 控制字元)

@-成員

成員名稱**可以**以 @ 符號(U+0040 商業 @,「@」)開頭。以此方式命名的成員稱為「@-成員」。@-成員**可以**出現在文件中的任何位置。

本規範沒有提供關於 @-成員的含義或用法的指導,@-成員被認為是 實作語義。在本小節之外解釋本規範的定義和處理說明時,**必須**忽略 @-成員。例如,屬性 在上面定義為屬性物件的任何成員。但是,由於在解釋該定義時必須忽略 @-成員,因此屬性物件中出現的 @-成員不是屬性。

注意:除其他事項外,「@」成員可用於將 JSON-LD 數據添加到 JSON:API 文件中。此類文件應使用 額外的標頭 提供,以向 JSON-LD 客戶端傳達它們包含 JSON-LD 數據。

擴充成員

擴充功能引入的每個新成員的名稱**必須**以 擴充功能的名稱空間 作為前綴,後跟冒號 (:)。名稱的其餘部分**必須**遵守實作定義的 成員名稱 的規則。

擷取數據

可以通過向端點發送 GET 請求來擷取數據,包括資源和關係。

可以使用下面描述的選用功能進一步完善響應。

擷取資源

伺服器**必須**支援擷取作為以下提供的每個 URL 的資源數據:

  • 作為頂層連結物件一部分的 self 連結
  • 作為資源級連結物件一部分的 self 連結
  • 作為關係級連結物件一部分的 related 連結

例如,以下請求擷取文章集合:

GET /articles HTTP/1.1
Accept: application/vnd.api+json

以下請求擷取一篇文章:

GET /articles/1 HTTP/1.1
Accept: application/vnd.api+json

以下請求擷取文章的作者:

GET /articles/1/author HTTP/1.1
Accept: application/vnd.api+json

響應

200 OK

伺服器**必須**使用 200 OK 響應來回應成功擷取單個資源或資源集合的請求。

伺服器**必須**使用 資源物件 陣列或空陣列 ([]) 作為響應文件的主要數據來回應成功擷取資源集合的請求。

例如,對文章集合的 GET 請求可以返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    }
  }, {
    "type": "articles",
    "id": "2",
    "attributes": {
      "title": "Rails is Omakase"
    }
  }]
}

表示空集合的類似響應將是:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": []
}

伺服器**必須**使用作為響應文件的主要數據提供的 資源物件null 來回應成功擷取單個資源的請求。

僅當請求的 URL 可能對應於單個資源,但目前沒有對應時,null 才是適當的響應。

注意:例如,考慮一個擷取一對一相關資源連結的請求。當關係為空(例如連結未對應到任何資源)時,此請求將以 null 作為響應,否則以單個相關資源的 資源物件 作為響應。

例如,對單篇文章發出 GET 請求可能會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles/1"
  },
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "related": "http://example.com/articles/1/author"
        }
      }
    }
  }
}

如果上述文章的作者缺失,則對該相關資源發出 GET 請求會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles/1/author"
  },
  "data": null
}
404 Not Found(找不到)

伺服器在處理擷取不存在的單一資源的請求時,**必須**回應 404 Not Found,除非請求保證以 null 作為主要資料的 200 OK 回應(如上所述)。

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

擷取關聯

對於作為關聯的 links 物件一部分提供的每個作為 self 連結的關聯 URL,伺服器**必須**支援擷取其關聯資料。

例如,以下請求擷取有關文章評論的資料

GET /articles/1/relationships/comments HTTP/1.1
Accept: application/vnd.api+json

以下請求擷取有關文章作者的資料

GET /articles/1/relationships/author HTTP/1.1
Accept: application/vnd.api+json

回應

200 OK(成功)

伺服器**必須**以 200 OK 回應成功擷取關聯的請求。

回應文件中主要資料**必須**與 資源連結 的相應值匹配,如上文針對 關聯物件 所述。

頂層的 links 物件 **可以**包含 selfrelated 連結,如上文針對 關聯物件 所述。

例如,對一對一關聯連結的 URL 發出 GET 請求可能會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": {
    "type": "people",
    "id": "12"
  }
}

如果上述關聯為空,則對相同 URL 發出 GET 請求會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": null
}

對一對多關聯連結的 URL 發出 GET 請求可能會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

如果上述關聯為空,則對相同 URL 發出 GET 請求會返回

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": []
}
404 Not Found(找不到)

伺服器在處理擷取不存在的關聯連結 URL 的請求時,**必須**返回 404 Not Found

注意:當關聯的父資源不存在時,可能會發生這種情況。例如,當 /articles/1 不存在時,對 /articles/1/relationships/tags 的請求會返回 404 Not Found

如果關聯連結 URL 存在但關聯為空,則**必須**返回 200 OK,如上所述。

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

端點**可以**預設返回與主要資料相關的資源。

端點**可以**支援 include 查詢參數,允許客戶端自訂應返回哪些相關資源。

如果端點不支援 include 參數,則它**必須**以 400 Bad Request(錯誤請求)回應任何包含它的請求。

如果端點支援 include 參數且客戶端提供它

  • 伺服器的回應**必須**是具有 included 鍵的 複合文件,即使該 included 鍵持有空陣列(因為請求的關聯為空)。
  • 伺服器**不得**在 複合文件included 部分中包含未請求的 資源物件

include 參數的值**必須**是以逗號 (U+002C COMMA,",") 分隔的關聯路徑列表。關聯路徑是以點 (U+002E FULL-STOP,".") 分隔的 關聯 名稱列表。空值表示不應返回任何相關資源。

如果伺服器無法識別關聯路徑或不支援包含路徑中的資源,則它**必須**以 400 Bad Request(錯誤請求)回應。

注意:例如,關聯路徑可以是 comments.author,其中 comments 是列在 articles 資源物件 下的關聯,而 author 是列在 comments 資源物件 下的關聯。

例如,可以請求文章的評論

GET /articles/1?include=comments HTTP/1.1
Accept: application/vnd.api+json

為了請求與其他資源相關的資源,可以為每個關聯名稱指定以點分隔的路徑

GET /articles/1?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

注意:由於 複合文件 需要完整的連結(除非稀疏欄位集排除了關聯連結),因此多部分路徑中的中間資源必須與葉節點一起返回。例如,對 comments.author 請求的回應應包含 comments 以及每個 commentsauthor

注意:伺服器可以選擇將深度嵌套的關聯(例如 comments.author)公開為具有替代名稱(例如 commentAuthors)的直接關聯。這將允許客戶端請求 /articles/1?include=commentAuthors 而不是 /articles/1?include=comments.author。通過使用替代名稱公開嵌套關聯,伺服器仍然可以在複合文件中提供完整的連結,而無需包含可能不需要的中間資源。

可以在以逗號分隔的列表中請求多個相關資源

GET /articles/1?include=comments.author,ratings HTTP/1.1
Accept: application/vnd.api+json

此外,可以從關聯端點請求相關資源

GET /articles/1/relationships/comments?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

在這種情況下,主要資料將是表示文章評論連結的 資源識別符號物件 集合,而完整的評論和評論作者將作為包含的資料返回。

注意:本節適用於任何以主要資料回應的端點,無論請求類型如何。例如,伺服器可以支援包含相關資源以及創建資源或關聯的 POST 請求。

稀疏欄位集

客戶端**可以**通過包含 fields[TYPE] 查詢參數來請求端點僅在回應中基於類型返回特定 欄位

任何 fields[TYPE] 參數的值**必須**是以逗號 (U+002C COMMA,",") 分隔的列表,其中引用要返回的欄位的名稱。空值表示不應返回任何欄位。

如果客戶端請求給定資源類型的受限 欄位 集,則端點**不得**在其回應中包含該類型資源物件中的其他 欄位

如果客戶端沒有為給定資源類型指定 欄位 集,則伺服器**可以**發送該資源類型的所有欄位、欄位子集或不發送欄位。

GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json

注意:上述 URI 範例顯示未編碼的 [] 字元僅僅是為了便於閱讀。實際上,這些字元應進行百分比編碼。請參閱“參數名稱中的方括號”。

注意:本節適用於任何以資源作為主要或包含資料回應的端點,無論請求類型如何。例如,伺服器可以支援稀疏欄位集以及創建資源的 POST 請求。

排序

伺服器**可以**選擇支援根據一個或多個條件(“排序欄位”)對資源集合進行排序的請求。

注意:雖然建議這樣做,但排序欄位不一定需要對應資源屬性和關聯名稱。

注意:建議使用以點 (U+002E FULL-STOP,".") 分隔的排序欄位來請求基於關聯屬性的排序。例如,可以使用排序欄位 author.name 來請求根據 author 關聯的 name 屬性對主要資料進行排序。

端點**可以**支援使用 sort 查詢參數對主要資料進行排序的請求。sort 的值**必須**表示排序欄位。

GET /people?sort=age HTTP/1.1
Accept: application/vnd.api+json

端點**可以**通過允許以逗號 (U+002C COMMA,",") 分隔的排序欄位來支援多個排序欄位。排序欄位**應該**按指定的順序應用。

GET /people?sort=age,name HTTP/1.1
Accept: application/vnd.api+json

每個排序欄位的排序順序**必須**是升序,除非它以減號 (U+002D HYPHEN-MINUS,"-") 作為前綴,在這種情況下它**必須**是降序。

GET /articles?sort=-created,title HTTP/1.1
Accept: application/vnd.api+json

以上範例應該先回傳最新的文章。任何在同一天建立的文章將會按照標題以升冪字母順序排序。

如果伺服器不支援查詢參數 sort 中指定的排序方式,它**必須**回傳 400 Bad Request

如果伺服器支援排序,並且客戶端透過查詢參數 sort 要求排序,伺服器**必須**根據指定的條件回傳已排序的頂層 data 陣列元素。如果未指定請求參數 sort,伺服器**可以**對頂層 data 套用預設排序規則。

注意:此章節適用於任何以資源集合作為主要資料回應的端點,不論請求類型為何。

分頁

伺服器**可以**選擇將回應中回傳的資源數量限制為可用集合的子集(「頁面」)。

伺服器**可以**提供連結來瀏覽分頁的資料集(「分頁連結」)。

分頁連結**必須**出現在對應於集合的連結物件中。要對主要資料進行分頁,請在頂層 links 物件中提供分頁連結。要對 複合文件 中回傳的包含集合進行分頁,請在對應的連結物件中提供分頁連結。

分頁連結**必須**使用以下鍵值:

  • first:第一頁資料
  • last:最後一頁資料
  • prev:上一頁資料
  • next:下一頁資料

若特定連結不可用,鍵值**必須**省略或設為 null 值。

在分頁連結命名中表達的順序概念**必須**與 JSON:API 的 排序規則 保持一致。

page 查詢參數系列 保留用於分頁。伺服器和客戶端**應該**使用這些參數進行分頁操作。

注意:JSON API 不限制伺服器使用的分頁策略,但無論採用何種策略,都可以使用 page 查詢參數系列。例如,基於頁面的策略可能會使用 page[number]page[size] 等查詢參數,而基於游標的策略可能會使用 page[cursor]

注意:此章節適用於任何以資源集合作為主要資料回應的端點,不論請求類型為何。

過濾

filter 查詢參數系列 保留用於過濾資料。伺服器和客戶端**應該**使用這些參數進行過濾操作。

注意:JSON API 不限制伺服器支援的策略。

建立、更新和刪除資源

伺服器**可以**允許建立給定類型的資源。它也**可以**允許修改或刪除現有資源。

請求**必須**完全成功或失敗(在單個「交易」中)。不允許部分更新。

注意:在 JSON:API 的請求和回應中,每個 資源物件 都需要 type 成員。在某些情況下,例如當 POST 到表示異質資料的端點時,無法從端點推斷 type。但是,選擇何時需要它會造成混淆;很難記住何時需要它,何時不需要它。因此,為了提高一致性並減少混淆,始終需要 type

建立資源

可以透過向代表資源集合的 URL 發送 POST 請求來建立資源。請求**必須**包含單個 資源物件 作為主要資料。資源物件**必須**至少包含一個 type 成員。

例如,可以使用以下請求建立新的照片:

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "relationships": {
      "photographer": {
        "data": { "type": "people", "id": "9" }
      }
    }
  }
}

如果在 資源物件relationships 成員中提供了關聯,則其值**必須**是具有 data 成員的關聯物件。此鍵的值表示新資源將具有的 連結

客戶端產生的 ID

伺服器**可以**接受客戶端產生的 ID 以及建立資源的請求。ID**必須**使用 id 鍵指定,其值**必須**是全域唯一識別碼。客戶端**應該**使用 RFC 4122 [RFC4122] 中描述的正確產生和格式化的 *UUID*。

注意:在某些情況下,例如從其他來源導入資料,可以使用 UUID 以外的其他東西,但仍然可以保證全域唯一。除非您 100% 確定您使用的策略確實會產生全域唯一識別碼,否則不要使用 UUID 以外的任何東西。

例如

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }
  }
}

對於不支援使用客戶端產生的 ID 建立資源的請求,伺服器**必須**回傳 403 Forbidden

回應

201 Created

如果請求的資源已成功建立,並且伺服器以任何方式更改了資源(例如,透過分配 id),則伺服器**必須**回傳 201 Created 回應和包含資源作為主要資料的文件。

為了符合 RFC 7231,回應**應該**包含一個 Location 標頭,用於識別新建立資源的位置。

如果回應回傳的 資源物件links 成員中包含 self 鍵,並且提供了 Location 標頭,則 self 成員的值**必須**與 Location 標頭的值相符。

HTTP/1.1 201 Created
Location: http://example.com/photos/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "links": {
      "self": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

如果請求的資源已成功建立,並且伺服器未以任何方式更改資源(例如,透過分配 idcreatedAt 屬性),伺服器**可以**回傳 201 Created 回應和不包含主要資料的文件。其他頂級成員,例如 meta,可以包含在回應文件中。

注意:只有接受 客戶端產生的 ID 的伺服器才能避免為新資源分配 id

202 Accepted

如果已接受處理建立資源的請求,但在伺服器回應時尚未完成處理,則伺服器**必須**回傳 202 Accepted 狀態碼。

204 No Content

如果請求的資源已成功建立,並且伺服器未以任何方式更改資源(例如,透過分配 idcreatedAt 屬性),則伺服器**必須**回傳 201 Created 狀態碼和回應文件(如上所述)或 204 No Content 狀態碼,且不包含回應文件。

403 Forbidden

對於不支援的建立資源請求,伺服器**可以**回傳 403 Forbidden

404 Not Found

處理引用不存在的相關資源的請求時,伺服器**必須**回傳 404 Not Found

409 Conflict

處理使用已存在的客戶端產生的 ID 建立資源的 POST 請求時,伺服器**必須**回傳 409 Conflict

處理 POST 請求時,如果 資源物件type 不在構成端點所代表集合的類型之中,伺服器**必須**回傳 409 Conflict

伺服器**應該**包含錯誤詳細資訊,並提供足夠的資訊來識別衝突的來源。

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

更新資源

可以透過向代表資源的 URL 發送 PATCH 請求來更新資源。

資源的 URL 可以在資源物件的 self 連結中取得。或者,當 GET 請求回傳單個 資源物件 作為主要資料時,可以使用相同的請求 URL 進行更新。

PATCH 請求**必須**包含單個 資源物件 作為主要資料。資源物件**必須**包含 typeid 成員。

例如

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not"
    }
  }
}

更新資源的屬性

資源的任何或所有 屬性**可以**包含在 PATCH 請求中包含的資源物件中。

如果請求未包含資源的所有 屬性,則伺服器**必須**將缺少的 屬性 解釋為包含其目前值。伺服器**不得**將缺少的屬性解釋為 null 值。

例如,以下 PATCH 請求被解釋為僅更新文章的 titletext 屬性的請求:

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not",
      "text": "TLDR; It's complicated... but check your test coverage regardless."
    }
  }
}

更新資源的關聯

資源的任何或所有 關聯**可以**包含在 PATCH 請求中包含的資源物件中。

如果請求沒有包含資源的所有關聯,伺服器**必須**將缺少的關聯解釋為包含其目前的值。它**不得**將它們解釋為null或空值。

如果在PATCH請求中資源物件的relationships成員中提供了關聯,則其值**必須**是具有data成員的關聯物件。關聯的值將被此成員中指定的值取代。

例如,以下PATCH請求將更新文章的author關聯

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "1" }
      }
    }
  }
}

同樣地,以下PATCH請求會完全取代文章的tags

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "2" },
          { "type": "tags", "id": "3" }
        ]
      }
    }
  }
}

伺服器**可以**拒絕嘗試完全取代一對多關聯。在這種情況下,伺服器**必須**拒絕整個更新,並返回403 Forbidden回應。

注意:由於完全取代可能是一個非常危險的操作,伺服器可以選擇不允許它。例如,如果伺服器沒有向客戶端提供關聯物件的完整列表,並且不想允許刪除客戶端沒有看到的記錄,則伺服器可以拒絕完全取代。

回應

200 OK

如果伺服器接受更新,但也以請求未指定的方式更改目標資源(例如,更新updatedAt屬性或計算的sha),它**必須**返回200 OK回應和包含已更新資源作為主要數據的文件。

如果更新成功且伺服器未以請求未指定的方式更改目標資源,伺服器**可以**返回包含無主要數據文件的200 OK回應。其他頂級成員,例如meta,可以包含在回應文件中。

202 Accepted(已接受)

如果已接受更新請求進行處理,但在伺服器回應時尚未完成處理,則伺服器**必須**返回202 Accepted狀態碼。

204 No Content(無內容)

如果更新成功,且伺服器未以請求未指定的方式更改目標資源,則伺服器**必須**返回200 OK狀態碼和回應文件(如上所述)或不帶回應文件的204 No Content狀態碼。

403 Forbidden(禁止)

對於不支持的更新資源或關聯的請求,伺服器**必須**返回403 Forbidden

404 Not Found(未找到)

處理修改不存在的資源的請求時,伺服器**必須**返回404 Not Found

處理引用不存在的相關資源的請求時,伺服器**必須**回傳 404 Not Found

409 Conflict(衝突)

如果更新會違反其他伺服器強制執行的約束(例如id以外的屬性的唯一性約束),則伺服器在處理PATCH請求以更新資源時**可以**返回409 Conflict

如果資源物件的typeid與伺服器的端點不匹配,則伺服器處理PATCH請求時**必須**返回409 Conflict

伺服器**應該**包含錯誤詳細資訊,並提供足夠的資訊來識別衝突的來源。

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

更新關聯

儘管可以與資源一起修改關聯(如上所述),但 JSON:API 也支持在關聯連結的 URL 上獨立更新關聯。

注意:關聯的更新不會公開底層伺服器語義,例如外鍵。此外,可以更新關聯而不必影響相關資源。例如,如果一篇文章有多個作者,則可以從文章中移除其中一位作者,而無需刪除該人本身。同樣,如果一篇文章有多個標籤,則可以新增或移除標籤。在伺服器端,第一個範例可以使用外鍵實作,而第二個範例可以使用連接表實作,但在兩種情況下 JSON:API 協定都是相同的。

注意:如果刪除關聯(作為垃圾收集措施),伺服器可以選擇刪除底層資源。

更新一對一關聯

可以通過向一對一關聯連結的 URL 發送PATCH請求來更新一對一關聯。

PATCH請求**必須**包含一個名為data的頂級成員,其中包含以下其中一項

例如,以下請求更新文章的作者

PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": { "type": "people", "id": "12" }
}

以下請求清除同一篇文章的作者

PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": null
}

如果關聯更新成功,則伺服器**必須**返回成功的回應。

更新一對多關聯

可以通過向一對多關聯連結的 URL 發送PATCHPOSTDELETE請求來更新一對多關聯。

對於所有請求類型,主體**必須**包含一個data成員,其值是一個空陣列或一個資源識別碼物件陣列。

如果客戶端向來自一對多關聯連結的 URL 發出PATCH請求,則伺服器**必須**完全取代關聯的每個成員,如果找不到或無法訪問某些資源,則返回適當的錯誤回應,或者如果伺服器不允許完全取代,則返回403 Forbidden回應。

例如,以下請求會取代文章的每個標籤

PATCH /articles/1/relationships/tags HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

以下請求會清除文章的每個標籤

PATCH /articles/1/relationships/tags HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": []
}

如果客戶端向來自關聯連結的 URL 發出POST請求,則伺服器**必須**將指定的成員新增到關聯中,除非它們已經存在。如果給定的typeid已存在於關聯中,則伺服器**不得**再次新增它。

注意:這與使用外鍵進行一對多關聯的資料庫語義相匹配。基於文件的儲存應在附加之前檢查一對多關聯以避免重複。

如果所有指定的資源都可以新增到關聯中或已經存在於關聯中,則伺服器**必須**返回成功的回應。

注意:這種方法可確保如果伺服器的狀態與請求的狀態匹配,則請求成功,並有助於避免多個客戶端對關聯進行相同更改而導致的無謂競爭情況。

在以下範例中,ID 為123的評論會新增到 ID 為1的文章的評論列表中

POST /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "123" }
  ]
}

如果客戶端向來自關聯連結的 URL 發出DELETE請求,則伺服器**必須**從關聯中刪除指定的成員或返回403 Forbidden回應。如果所有指定的資源都可以從關聯中移除或已經從關聯中遺失,則伺服器**必須**返回成功的回應。

注意:如上所述,對於POST請求,這種方法有助於避免多個客戶端進行相同更改之間的無謂競爭情況。

關聯成員的指定方式與POST請求中的方式相同。

在以下範例中,ID 為1213的評論會從 ID 為1的文章的評論列表中移除

DELETE /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "12" },
    { "type": "comments", "id": "13" }
  ]
}

注意:RFC 7231 規定 DELETE 請求可以包含主體,但伺服器可以拒絕該請求。此規範定義了伺服器的語義,我們正在為 JSON:API 定義其語義。

回應

200 OK

如果伺服器接受更新,但也以請求未指定的方式更改目標關聯,則它**必須**返回200 OK回應和包含已更新關聯數據作為其主要數據的文件。

如果更新成功且伺服器未以請求未指定的方式更改目標關聯,伺服器**可以**返回包含無主要數據文件的200 OK回應。其他頂級成員,例如meta,可以包含在回應文件中。

202 Accepted(已接受)

如果已接受關聯更新請求進行處理,但在伺服器回應時尚未完成處理,則伺服器**必須**返回202 Accepted狀態碼。

204 無內容

如果更新成功且伺服器除了請求指定的變更之外沒有以其他方式變更目標關聯,則伺服器**必須**返回 200 OK 狀態碼和回應文件(如上所述)或 204 無內容 狀態碼,且無回應文件。

注意:這是將 POST 請求發送到多對多 關聯連結 的 URL 時,該關聯已存在的適當回應。這也是將 DELETE 請求發送到多對多 關聯連結 的 URL 時,該關聯不存在的適當回應。

403 Forbidden(禁止)

對於不支援的更新關聯請求,伺服器**必須**返回 403 禁止

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

刪除資源

可以透過向代表資源的 URL 發送 DELETE 請求來刪除資源。

DELETE /photos/1 HTTP/1.1
Accept: application/vnd.api+json

回應

200 OK

如果刪除請求成功,伺服器**可以**返回包含沒有主要資料的文檔的 200 OK 回應。其他頂級成員,例如 meta,可以包含在回應文件中。

202 已接受

如果已接受刪除請求進行處理,但在伺服器回應時尚未完成處理,則伺服器**必須**返回 202 已接受 狀態碼。

204 無內容

如果刪除請求成功,伺服器**必須**返回 200 OK 狀態碼和回應文件(如上所述)或 204 無內容 狀態碼,且無回應文件。

404 找不到

如果刪除請求由於資源不存在而失敗,伺服器**應該**返回 404 找不到 狀態碼。

其他回應

伺服器**可以**回應其他 HTTP 狀態碼。

伺服器**可以**在錯誤回應中包含錯誤詳細資訊

伺服器**必須**根據 HTTP 語義 準備回應,客戶端**必須**根據其解釋回應。

查詢參數

查詢參數家族

儘管「查詢參數」是日常網頁開發中的常用術語,但它並不是一個標準化的概念。因此,JSON:API 提供了它自己的 查詢參數定義

在大多數情況下,JSON:API 的定義與口語用法一致,其細節可以安全地忽略。但是,此定義的一個重要結果是,像以下這樣的 URL 被認為具有兩個不同的查詢參數:

/?page[offset]=0&page[limit]=10

這兩個參數分別命名為 page[offset]page[limit];沒有單個 page 參數。

然而,在實踐中,像 page[offset]page[limit] 這樣的參數通常一起定義和處理,並且將它們統稱為一個集合很方便。因此,JSON:API 引入了查詢參數家族的概念。

「查詢參數家族」是所有查詢參數的集合,其名稱以「基名」開頭,後跟零個或多個空方括號(即 [])、方括號括起來的合法 成員名稱 或方括號括起來的點分隔的合法成員名稱列表。該家族由其基名引用。

例如,filter 查詢參數家族包含以下命名的參數:filterfilter[x]filter[]filter[x][]filter[][]filter[x][y]filter[x.y] 等。但是,filter[_] 不是家族中有效的參數名稱,因為 _ 不是有效的 成員名稱

注意:點分隔的合法成員名稱列表旨在用於關聯路徑。例如,這允許在查詢參數中使用關聯路徑的過濾策略,如 [排序][擷取排序] 中定義的,例如 GET /posts?sort=author.name&filter[author.status]=active

擴充套件特定的查詢參數

擴充套件引入的每個查詢參數的基名**必須**以擴充套件的名稱空間加上冒號(:)作為前綴。基名的其餘部分**必須**僅包含字元 [a-z](U+0061 到 U+007A,「a-z」)。

實作特定的查詢參數

實作**可以**支援自定義查詢參數。但是,這些查詢參數的名稱**必須**來自 家族,其基名是合法的 成員名稱,並且還包含至少一個非 a-z 字元(即,在 U+0061 到 U+007A 之外)。

**建議**使用大寫字母(例如 camelCasing)來滿足上述要求。

如果伺服器遇到不符合上述命名約定的查詢參數,或者伺服器不知道如何將其作為本規範中的查詢參數進行處理,則它**必須**返回 400 不良請求

注意:透過禁止使用僅包含字元 [a-z] 的查詢參數,JSON:API 保留了以後標準化其他查詢參數的能力,而不會與現有實作衝突。

錯誤

處理錯誤

伺服器**可以**選擇在遇到問題後立即停止處理,或者**可以**繼續處理並遇到多個問題。例如,伺服器可能會處理多個屬性,然後在單個回應中返回多個驗證問題。

當伺服器針對單個請求遇到多個問題時,**應該**在回應中使用最通用的 HTTP 錯誤碼。例如,400 不良請求 可能適用於多個 4xx 錯誤,或者 500 內部伺服器錯誤 可能適用於多個 5xx 錯誤。

錯誤物件

錯誤物件提供有關在執行操作時遇到的問題的額外資訊。錯誤物件**必須**作為 JSON:API 文件頂層中由 errors 鍵入的陣列返回。

錯誤物件**可以**具有以下成員,並且**必須**包含以下至少一項:

  • id:此特定問題發生的唯一識別碼。
  • links:一個 連結物件,**可以**包含以下成員:
    • about:一個 連結,指向有關此特定問題發生的更多詳細資訊。取消參考時,此 URI **應該**返回錯誤的人類可讀描述。
    • type:一個 連結,識別此特定錯誤所屬的錯誤類型。此 URI **應該**可以取消參考到一般錯誤的人類可讀說明。
  • status:適用於此問題的 HTTP 狀態碼,表示為字串值。這**應該**提供。
  • code:應用程式特定的錯誤碼,表示為字串值。
  • title:問題的簡短、人類可讀摘要,除本地化目的外,**不應**在問題的每次發生時更改。
  • detail:針對此特定問題發生的人類可讀說明。與 title 一樣,此欄位的值可以本地化。
  • source:包含對錯誤主要來源的參考的物件。它**應該**包含以下成員之一或省略:
    • pointer:一個 JSON Pointer [RFC6901],指向請求文件中導致錯誤的值 [例如,主要資料物件的 "/data" 或特定屬性的 "/data/attributes/title"]。這**必須**指向請求文件中存在的值;如果它不存在,則用戶端**應該**簡單地忽略指標。
    • parameter:一個字串,指示哪個 URI 查詢參數導致錯誤。
    • header:一個字串,指示導致錯誤的單個請求標頭的名稱。
  • meta:包含有關錯誤的非標準中繼資訊的 meta 物件

附錄

查詢參數詳細資訊

解析/序列化

查詢參數是從 URI 的查詢字串中提取或序列化為 URI 的查詢字串的名稱-值對。

要從 URI 中提取查詢參數,實作**必須**執行 URI 的查詢字串(不包括前導問號),透過 application/x-www-form-urlencoded 解析演算法,但有一個例外:JSON:API 允許定義查詢參數用法的規範提供其自己的規則,用於從 application/x-www-form-urlencoded 解析演算法的步驟 3.2 和 3.3 中識別的 value 位元組中解析參數的值。結果值可能不是字串。

注意:通常,伺服器和瀏覽器內建的查詢字串解析將與上述指定的過程匹配,因此大多數實作不必擔心這一點。

引用 application/x-www-form-urlencoded 格式是因為它是幾乎所有查詢字串今天使用的 a=b&c=d 風格的基礎。

但是,application/x-www-form-urlencoded 解析包含奇怪的歷史產物,即 + 字元必須被視為空格,並且它要求所有值在解析期間都要進行百分比解碼,這使得無法使用 RFC 3986 分隔符號 作為分隔符號。這些問題促使 JSON:API 定義了上述例外。

類似地,要將查詢參數序列化為 URI,實作**必須**使用 application/x-www-form-urlencoded 序列化器,但相應的例外是參數的值(但不是其名稱)可以與該演算法要求的不同方式進行序列化,前提是序列化不干擾解析回結果 URI 的能力。

參數名稱中的方括號

透過查詢參數家族,JSON:API 允許查詢參數的名稱包含方括號(即 U+005B「[」和 U+005D「]」)。

根據上述查詢參數序列化規則,符合規範的實作會將這些方括號進行百分比編碼。然而,有些 URI 生成器 — 尤其是瀏覽器 — 並不總是會編碼它們。伺服器**應該**接受在查詢參數名稱中未編碼這些方括號的請求。如果伺服器確實接受這些請求,它**必須**將該請求視為與對方括號進行百分比編碼的請求相同。