[译] 怎样使用GraphQL - 3.核心概念

英文原版地址:https://www.howtographql.com/...

在本章中,你将了解GraphQL的一些基本语言结构。 内容包括,初次认识,定义类型,查询和mutation的语法。我们还为你准备了一个基于graphql-up的沙箱环境,你可以使用它来实验学到的内容。

视图定义语言(SDL)

GraphQL有自己的类型系统,用于定义API的Schema。编写Schema的语法称为SDL。

以下是使用SDL定义简单类型Person的示例:

type Person {
  name: String!
  age: Int!
}

这个Person类型有两个字段,nameage,是String和Int类型的,紧跟着的 ! 表示该字段是必需的。

可以在类型之间相互使用。在博客应用的例子中,一个Person可以与一个Post相关联:

type Post {
  title: String!
  author: Person!
}

同时,另一方面,Person类型中添加相应类型。

type Person {
  name: String!
  age: Int!
  posts: [Post!]!
}

请注意,我们刚刚创建了PersonPost之间的一对多关系,因为Person上的posts字段实际上是一个帖子数组。

使用查询语句获取数据

使用REST API时,会从指定接口加载数据。每个接口都明确定义了返回的数据结构。这意味着客户端需要的数据,已经在URL中制定好了。

GraphQL中采用的方式截然不同。GraphQL的API通常只暴露一个接口,而不是返回固定数据结构的多个接口。 这是因为返回的数据结构不是一成不变的,而是灵活的,让客户端来决定真正需要的是什么数据。

这意味着客户端需要向服务端发送更多信息来告知所需求的数据 - 这个额外信息称为查询。

基本查询

我们来看看客户端发送给服务端的简单查询示例:

{
  allPersons {
    name
  }
}

在这查询中,allPersons字段称为查询的根字段。根字段之后的所有内容称为查询的payload。此查询中,指定的唯一payload字段是name

此查询将返回当前存储在数据库中的所有的人员列表。返回的示例如下:

{
  "allPersons": [
    { "name": "Johnny" },
    { "name": "Sarah" },
    { "name": "Alice" }
  ]
}

请注意,每个Person在响应结果中只有name一个属性,服务端并没有返回age属性。 这正是因为name是在查询中指定的唯一字段。

如果客户端也想要获取年龄属性,那么要做的,仅仅是调整一下查询语句,在查询的payload中加入新的字段:

{
  allPersons {
    name
    age
  }
}

GraphQL的一个重要优势是,允许直接通过嵌套的方式查询信息。例如,如果想获取一个Person写的所有posts,可以简单地按照类型的结构来获取数据:

{
  allPersons {
    name
    age
    posts {
      title
    }
  }
}

查询时带上参数

在GraphQL中,每个在视图中定义的字段都可以拥有参数(零或多个)。例如,allPersons字段可以包含last参数,用来返回特定数量的Persons。相应的查询如下:

{
  allPersons(last: 2) {
    name
  }
}

通过Mutation操作数据

在从服务端获取到数据之后,主流的应用程序总是要更改存储在后端的数据。使用GraphQL,这些更改是使用Mutation来完成的。 Mutation一般有这三种:

  • 创建新数据

  • 更新现有数据

  • 删除现有数据

Mutation遵循与查询相同的语法结构,但是它们始终需要从Mutation关键字开始。 以下是我们如何创建一个新的Person的例子:

mutation {
  createPerson(name: "Bob", age: 36) {
    name
    age
  }
}

请注意,与之前写的查询类似,mutation也有一个根字段,上面的例子中,这个字段是createPerson。 我们之前已经讲到过关于查询参数的内容。例子中,createPerson接受nameage两个参数。

像查询一样,我们还可以为mutation指定一个payload,我们可以在其中请求新建的Person对象的其他属性。 在我们的例子中,我们指定的是nameage,虽然我们的例子并不是很有意义,因为我们获取的是我们已知的数据。但我们已经清晰的了解到,当请求是mutation时,也能够指定查询信息,这体现了mutation的强大之处,允许在一次请求来回中,从服务器获取新数据!

上面的mutation的响应数据是这样的:

"createPerson": {
  "name": "Bob",
  "age": "36",
}

我们总是能了解到,当新增数据时,GraphQL会在服务端生成一个唯一的ID类型。扩展一下我们之前定义的Person类型,我们可以添加一个id字段,如下所示:

type Person {
  id: ID!
  name: String!
  age: Int!
}

现在,当创建一个新的Person时,可以直接在mutation的payload中查询id,这是事先在客户端不知道的信息:

mutation {
  createPerson(name: "Alice", age: 36) {
    id
  }
}

使用Subscription进行实时更新

今天,许多应用的另一个重要需求是与服务端进行实时连接,以便实时响应重要事件。针对这种场景,GraphQL提供了订阅的概念。

当客户端订阅了事件,它将与服务器建立一个稳定连接并保持住这个链接。任何时刻,当有事件触发时,服务端都会把相关信息推送到客户端。不同于查询和mutation,订阅代表的是将数据推送出去的的模式,而不是经典的“请求 - 响应”的模式。

订阅使用的语法和查询和mutation相同。我们用来订阅Person类型上的事件,如下所示:

subscription {
  newPerson {
    name
    age
  }
}

在客户端将此订阅发送到服务端之后,会建立起一个链接。之后,每当mutation被执,用来创建新的Person时,服务端就会把有关此人的信息发送给客户端:

{
  "newPerson": {
    "name": "Jane",
    "age": 23
  }
}

定义视图(Schema)

现在,你已经对查询,mutation和订阅有一个基本的了解,让我们将这些放在一起,学习如何编写一个视图,让你自己执行目前为止所有的示例。

视图是使用GraphQL API时最重要的概念之一。它指定了API的功能,并定义了客户端如何请求数据。它通常被视为服务器和客户端之间的协议。

通常,视图只是GraphQL类型的集合。 但是,在为API编写视图时,有一些特殊的根类型:

type Query { ... }
type Mutation { ... }
type Subscription { ... }

查询,mutation和订阅是客户端发送请求的入口点。要启用我们前面看到的allPersons查询,查询类型必须如下定义:

type Query {
  allPersons: [Person!]!
}

allPersons称为API的根字段。再考虑到,我们将last参数添加到allPersons的示例,我们必须如下定义Query:

type Query {
  allPersons(last: Int): [Person!]!
}

类似地,对于createPersonmutation,我们必须向Mutation类型添加一个根字段:

type Mutation {
  createPerson(name: String!, age: String!): Person!
}

请注意,根字段有两个参数,Person的nameage

最后,对于订阅,我们必须添加newPerson根字段:

type Subscription {
  newPerson: Person!
}

将所有整合在一起,这是你在本章中看到的所有查询和mutation的完整模式:

type Query {
  allPersons(last: Int): [Person!]!
}

type Mutation {
  createPerson(name: String!, age: String!): Person!
}

type Subscription {
  newPerson: Person!
}

type Person {
  name: String!
  age: Int!
  posts: [Post!]!
}

type Post {
  title: String!
  author: Person!
}

相关推荐