logo

Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll
04/09/2025, by Ivan

简而言之:使用类似 ?include=field_comments.uid 的查询字符串,可以一次性包含 field_comments 引用的所有实体,以及这些实体上 uid 引用的所有实体!


JSON:API 通过允许你指定关系路径并将其包含在响应文档中,帮助你减少 HTTP 请求。如何实现呢?

获取单个资源

获取文章

假设你有一篇带有两条评论的文章,并且这两条评论的作者是同一个人。如果不使用 includes,要获取这些数据,你需要先请求 GET /jsonapi/node/article/some-random-uuid

{
  "data": {
    "type": "node--article",
    "id": "some-random-uuid",
    "relationships": {
      "field_comments": {
        "links": {
          "related": {
            "href": "https://my.example.com/node/article/some-random-uuid/field_comments"
          }
        }
      }
    }
  }
}

获取评论

然后,你需要请求 GET /node/article/some-random-uuid/field_comments

{
  "data": [{
    "type": "comment",
    "id": "one-random-uuid",
    "relationships": {
      "uid": {
        "links": {
          "related": {
            "href": "https://my.example.com/comment/one-random-uuid/uid"
          }
        }
      }
    }
  }, {
    "type": "comment",
    "id": "two-random-uuid",
    "relationships": {
      "uid": {
        "links": {
          "related": {
            "href": "https://my.example.com/comment/two-random-uuid/uid"
          }
        }
      }
    }
  }
}

获取用户

接着,你还需要对 /comment/one-random-uuid/uid/comment/two-random-uuid/uid 发出两个请求。但在这个示例中我们知道,这两条评论的作者其实是同一个人,因此第二个请求完全没必要。

那么,includes 如何帮助我们呢?

使用 include 一次性获取所有数据

很简单!只需在原始请求 URL 上添加一个查询参数,指定你想要包含的关系字段名称,服务器就会自动查询这些数据,并将它们添加到原始响应文档中。

在我们的示例中,请求 URL 会是 GET /jsonapi/node/article/some-random-uuid?include=field_comments.uid。换句话说,你的意思是“请把文章上的 field_comments 字段的资源对象加进来,然后再把评论引用的 uid 字段的资源对象也加进来”。这些“关系路径”可以任意长,没有限制!

服务器返回的响应文档如下:

{
  "data": {
    "type": "node--article",
    "id": "some-random-uuid",
    "relationships": {
      "field_comments": {
        "data": [{
          "type": "comment",
          "id": "one-random-uuid",
        }, {
          "type": "comment",
          "id": "two-random-uuid",
        }],
        "links": {
          "related": {
            "href": "https://my.example.com/node/article/some-random-uuid/field_comments"
          }
        }
      }
    }
  },
  "included": [{
    "type": "comment",
    "id": "one-random-uuid",
    "relationships": {
      "uid": {
        "data": [{
          "type": "user",
          "id": "another-random-uuid",
        }],
        "links": {
          "related": {
            "href": "https://my.example.com/comment/one-random-uuid/uid"
          }
        }
      }
    }
  }, {
    "type": "comment",
    "id": "another-random-uuid",
    "relationships": {
      "uid": {
        "data": [{
          "type": "user",
          "id": "one-random-uuid",
        }],
        "links": {
          "related": {
            "href": "https://my.example.com/comment/two-random-uuid/uid"
          }
        }
      }
    }
  }, {
    "type": "user",
    "id": "another-random-uuid",
    "attributes": {
      "name": "c0wb0yC0d3r"
    }
  }]
}

是不是很酷?我们在一个请求中就得到了所有数据!注意,即使用户资源对象被引用了两次,它也只包含一次。这使响应体积更小。还要注意,现在每个关系对象中都有一个 data 键,这让你能够将包含的资源对象与引用它们的资源对象关联起来。

何时使用 include?

说到响应体积……在这个示例中,我们通过一次性获取所有资源节省了时间。但在某些情况下,包含相关资源对象可能会让响应体积过大,或导致首次字节时间(TTFB)变慢。这种情况下,发起多个并行请求可能更好。

集合与关系的 include

最后,include 查询参数同样适用于集合关系资源!在集合上使用 include 可以节省大量请求。

集合 include 示例

获取集合 include 的请求类似于 GET /jsonapi/node/article?include=uidincludeddata 分开(数组而不是对象),如下所示:

{
  "data": [{...}]
  "included": [{
    "type": "user",
    "id": "another-random-uuid",
    "attributes": {
      "name": "c0wb0yC0d3r"
    }
  }]
}

文章来源:Drupal 文档