共计 3944 个字符,预计需要花费 10 分钟才能阅读完成。
GraphQL 之根底篇 – 查问和变更
字段(Fields)
GraphQL 申请对象上的特定字段,例:
// 申请
{
hero { name
friends {name} }}
// 响应
{"data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker"}, {"name": "Han Solo"} ] } }}
咱们能够发现,查问和后果领有一样的构造和字段。这是 GraphQL 最重要的个性,因为这样一来,你就总是能失去你想要的数据,而服务器也精确地晓得客户端申请的字段。
参数(Arguments)
申请传参是必要的,也能够让查问变得更加灵便和不便,当然 GraphQL 也能够做到。
// 申请
{human(id: "1000") {
name
height }}
// 响应
{"data": { "human": { "name": "Luke Skywalker", "height": 1.72} }}
别名(Aliases)
当须要重命名返回的字段名时,别名就有能够起到作用,如下例能够将 hero 替换为 empireHero 和 jediHero。
// 申请
{empireHero: hero(episode: EMPIRE) {name} jediHero: hero(episode: JEDI) {name}}
// 响应
{"data": { "empireHero": { "name": "Luke Skywalker"}, "jediHero": {"name": "R2-D2"} }}
片段(Fragments)
当咱们的申请中有有反复字段须要展现时,别离列出可能会显得比拟臃肿,这就是为何 GraphQL 蕴含了称作片段的可复用单元,上面例子展现了如何应用片段解决上述场景:
// 申请
{leftComparison: hero(episode: EMPIRE) {...comparisonFields} rightComparison: hero(episode: JEDI) {...comparisonFields}}
fragment comparisonFields on Character { name
appearsIn friends {name}}
// 响应
{"data": { "leftComparison": { "name": "Luke Skywalker", "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI"], "friends": [{ "name": "Han Solo"} ] }, "rightComparison": {"name": "R2-D2", "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI"], "friends": [{ "name": "Leia Organa"} ] } }}
有了片段,能够大大简化咱们的代码。片段的概念常常用于将简单的利用数据需要宰割成小块,特地是你要将大量不同片段的 UI 组件组合成一个初始数据获取的时候。
操作名称(Operation name)
这之前,咱们都应用了简写句法,省略了 query 关键字和查问名称,然而生产中应用操作类型和操作名称能够使咱们代码缩小歧义。
上面的示例蕴含了作为操作类型的关键字 query 以及操作名称 HeroNameAndFriends:
// 申请
query HeroNameAndFriends { hero { name
friends {name} }}
// 响应
{"data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker"}, {"name": "Leia Organa"} ] } }}
操作类型能够是 query、mutation 或 subscription,形容你打算做什么类型的操作。操作类型是必须的,除非你应用查问简写语法,在这种状况下,你无奈为操作提供名称或变量定义。
操作名称是你的操作的有意义和明确的名称。
变量(Variables)
目前为止,咱们将参数写在了查问字符串内。然而在很多利用中,字段的参数可能是动静的,如下例,可使咱们的申请更加灵便。
// 定义变量
{"episode": "JEDI"}
// 申请
query HeroNameAndFriends($episode: Episode) {hero(episode: $episode) { name
friends {name} }}
变量定义(Variable definitions)
变量定义看上去像是上述查问中的 ($episode: Episode)。其工作形式跟类型语言中函数的参数定义一样。它以列出所有变量,变量前缀必须为 $,后跟其类型,本例中为 Episode。
变量定义能够是可选的或者必要的。上例中,Episode 后并没有 !,因而其是可选的。然而如果你传递变量的字段要求非空参数,那变量肯定是必要的。
默认变量(Default variables)
能够通过在查问中的类型定义前面附带默认值的形式,将默认值赋给变量。
query HeroNameAndFriends($episode: Episode = "JEDI") {hero(episode: $episode) { name
friends {name} }}
指令(Directives)
咱们可能须要应用变量动静地扭转咱们查问的构造,如下例:
// 定义变量
{"episode": "JEDI", "withFriends": false}
// 申请
query Hero($episode: Episode, $withFriends: Boolean!) {hero(episode: $episode) { name
friends @include(if: $withFriends) {name} }}
// 响应
{"data": { "hero": { "name": "R2-D2"} }}
咱们用了 GraphQL 中一种称作指令的新个性。一个指令能够附着在字段或者片段蕴含的字段上。
GraphQL 的外围标准蕴含两个指令:
- @include(if: Boolean) 仅在参数为 true 时,蕴含此字段。
- @skip(if: Boolean) 如果参数为 true,跳过此字段。
变更(Mutations)
GraphQL 建了一个约定来标准任何写入的操作,都应该显式通过变更(mutation)来发送。
// 定义变量
{"ep": "JEDI", "review": { "stars": 5, "commentary": "This is a great movie!"}}
// 变更申请
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {createReview(episode: $ep, review: $review) {stars commentary}}
// 响应
{"data": { "createReview": { "stars": 5, "commentary": "This is a great movie!"} }}
一个变更也能蕴含多个字段,一如查问。查问和变更之间名称之外的一个重要区别是:
查问字段时,是并行执行,而变更字段时,是线性执行,一个接着一个。
这意味着如果咱们一个申请中发送了两个 incrementCredits 变更,第一个保障在第二个之前执行,以确保咱们不会呈现竞态。
内联片段(Inline Fragments)
如果你查问的字段返回的是接口或者联结类型,那么你可能须要应用内联片段来取出上层具体类型的数据:
// 定义变量
{"ep": "JEDI"}
// 申请
query HeroForEpisode($ep: Episode!) {hero(episode: $ep) { name
... on Droid {primaryFunction} ... on Human {height} }}
// 响应
{"data": { "hero": { "name": "R2-D2", "primaryFunction": "Astromech"} }}
这个查问中,hero 字段返回 Character 类型,取决于 episode 参数,其可能是 Human 或者 Droid 类型。在间接抉择的状况下,你只能申请 Character 上存在的字段,譬如 name。
如果要申请具体类型上的字段,你须要应用一个类型条件内联片段。因为第一个片段标注为 … on Droid,primaryFunction 仅在 hero 返回的 Character 为 Droid 类型时才会执行。同理实用于 Human 类型的 height 字段。
具名片段也能够用于同样的状况,因为具名片段总是附带了一个类型。
元字段(Meta fields)
某些状况下,你并不知道你将从 GraphQL 服务取得什么类型,这时候你就须要一些办法在客户端来决定如何解决这些数据。GraphQL 容许你在查问的任何地位申请 __typename,一个元字段,以取得那个地位的对象类型名称。
// 申请
{search(text: "an") {
__typename
... on Human {name} ... on Droid {name} ... on Starship {name} }}
// 响应
{"data": { "search": [ { "__typename": "Human", "name": "Han Solo"}, {"__typename": "Human", "name": "Leia Organa"}, {"__typename": "Starship", "name": "TIE Advanced x1"} ] }}
下面的查问中,search 返回了一个联结类型,其可能是三种选项之一。没有 __typename 字段的状况下,简直不可能在客户端分辨开这三个不同的类型。
参考资料:
https://graphql.cn/learn/quer…