【译】GraphQL 初学者指南

API 是互联网行业讨论最多的术语之一,可是不少人并不确切知道 API 究竟是什么。基本上,API 表明应用程序编程接口(Application Programming Interface)。顾名思义,它至关于一个“界面”,令人们(开发人员、用户、消费者)可以经过它与数据进行交互。php

你能够理解为 API 就像是个酒保,你向酒保要一杯酒,他便把一杯你想要的酒递给你,看起来很简单的事,还有什么问题呢?git

构建 API 不是一件困难的事,但学习和理解具体的 API 可能存在必定的困难。多数开发者都会使用你的 API 去开发功能或者只是消费数据,这就要求 API 须要尽量保持干净、直观。精心设计、直观性强的 API 会很是容易理解和使用。github

一直以来,咱们都在用 REST 来构建 API,使用这种方式会存在一些问题,例如:数据库

  • 多端点
  • 开发人员学习理解 API 的成本比较高
  • API 的信息过分和信息不足问题

为了解决以上的相似问题,Facebook 创造了 GraphQL。我认为 GraphQL 是当代构建 API 的最佳方式,本文将阐述为何你应该开始学习 GraphQL,让你了解 GraphQL 的工做原理,以及如何使用 GraphQL 建立设计精良、高效而且功能强大的 API。npm

你可能已经据说过 GraphQL,由于不少开发者和公司都在使用它。因为 GraphQL 是开源的,因此社区也是很庞大的存在。让咱们在实践中学习 GraphQL 的工做原理,领略它的魔力了。编程

什么是GraphQL?

GraphQL (译者注:中文文档)是 Facebook 开发的一种开源查询语言。它为咱们提供了一种更有效的方式来设计、建立和消费咱们的 API 。基本上,它是 REST 的替代品。json

GraphQL 有不少功能,例如:数组

  1. 咱们能够编写本身所需的数据,并得到所需的数据。不用再像咱们习惯使用的 REST 那样过分获取信息
  2. GraphQL 为咱们提供了单个端点,再也不为同一 API 提供版本2或版本3。
  3. GraphQL 是强类型的,因此咱们能够在执行以前在 GraphQL 类型系统中验证查询。有助于构建更强大的 API。

这是对 GraphQL 的基本介绍,解释了为何它如此强大以及为何它现在得到了不少人气。若是想了解更多相关信息,我建议访问 GraphQL 网站去了解。浏览器

入门

本文主要目的不是学习如何配置 GraphQL 服务器,因此咱们如今不会深刻研究。本文的目标是了解 GraphQL 在实践中的工做原理,所以咱们将使用一个叫作☄️Traderpack的零配置GraphQL服务器库。bash

第一步,咱们须要建立一个新文件夹,你能够随意命名。我将它命名为 graphql-server :

mkdir graphql-server
复制代码

假定你已经在本身的机器中安装了 npm 或 yarn。若是你不知道它们是什么,npm 和 yarn 是 JavaScript 编程语言的包管理器。对于 Node.js,默认包管理器是 npm。

在建立的文件夹中,输入如下命令:

npm init -y
复制代码

若是你使用 yarn :

yarn init 
复制代码

npm 会建立一个 package.json 文件,项目安装的全部依赖项和命令都在这个文件中。

接下来,咱们来安装本项目要使用的惟一依赖项,☄️Traderpack 容许你建立零配置的 GraphQL 服务器。因为咱们刚刚开始使用 GraphQL,这将帮助咱们继续学习更多内容,而没必要担忧服务器配置。

打开终端进入项目文件夹,键入如下命令:

npm install --save-dev graphpack
复制代码

若是你使用 yarn,应该这样:

yarn add --dev graphpack
复制代码

安装 Graphpack 以后,转到 package.json 文件中的脚本,并在其中输入如下代码:

"scripts": {
    "dev": "graphpack",
    "build": "graphpack build"
}
复制代码

咱们将建立一个名为 src 的文件夹做为整个服务器中惟一的文件夹,而后在 src 文件夹中建立三个文件。

译者注:使用 VSCode 的童鞋能够安装 `GraphQL for VSCode` 插件进行语法高亮

首先,咱们建立第一个文件,名叫 schema.graphql,并在这个文件中输入如下代码:

type Query {
  hello: String
}
复制代码

这个 schema.graphql 文件将是咱们的整个 GraphQL 架构,稍后我会解释它的做用。

接下来,在 src 文件夹中建立第二个文件 resolvers.js,并在这个文件中输入如下代码:

import { users } from "./db"

const resolvers = {
  Query: {
    hello: () => "Hello World!"
  }
}

export default resolvers
复制代码

这个 resolvers.js 文件将是咱们提供将 GraphQL 操做转换为数据的指令的方式。

最后,在src文件夹中建立第三个文件 db.js,并在这个文件中输入如下代码:

export let users = [
  { id: 1, name: "John Doe", email: "john@gmail.com", age: 22 },
  { id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }
]
复制代码

在本教程中,咱们没有使用真实数据库。因此这个 db.js 文件将模拟数据库,仅用于学习目的。

如今咱们的src文件夹应以下所示:

src
  |--db.js
  |--resolvers.js
  |--schema.graphql
复制代码

如今,若是你运行命令 npm run dev,或者若是你正在使用yarn,则运行 yarn dev,应该在终端中看到此输出:

如今能够用浏览器打开 localhost:4000,这意味着咱们已准备好开始在 GraphQL 中编写咱们的第一个 queries(查询),mutations(突变)和 subscriptions(订阅)。

若是感兴趣能够看看 GraphQL Playground,这是一个功能强大的 GraphQL IDE,可用于更好的开发工做流程。若是你想了解有关 GraphQL Playground 的更多信息,请单击此处

Schema

GraphQL 有本身的语言类型,用于编写 Schema(模式)。这是一种人类可读的模式语法,称为 Schema Definition Language - 模式定义语言(SDL)。不管使用何种技术,SDL都是相同的 - 你能够将其用于你想要的任何语言或框架。这种模式语言很是有用,由于它会让你很容易直观的理解你的 API 将具备哪些类型。

Types

Types(类型)是 GraphQL 最重要的特性之一。Types 是自定义对象,表示 API 的外观。举个例子,若是你正在构建社交媒体应用程序,那么你的 API 可能会有 PostsUsersLikesGroups 等 Types。

Types 下有 fields(字段),这些字段返回特定类型的数据。例如,咱们要建立一个 User 类型,咱们应该有 nameemailage 等字段。字段能够是任何类型,并始终返回一种数据类型,好比 Int、Float、String、Boolean、ID、对象类型列表或自定义对象类型。

如今编写咱们的第一个 Type,转到 schema.graphql 文件并用如下内容替换已存在的 Query 类型:

type User {
  id: ID!
  name: String!
  email: String!
  age: Int
}
复制代码

每一个 User 都将拥有一个 ID,所以咱们为其提供了 ID 类型。User 也会有一个 nameemail,因此咱们给它们 String 类型,年龄咱们给了 Int 类型。很简单吧?

数据类型后面的 ! 表示该字段非空(non-nullable),这意味着这些带 ! 的字段必须在每一个查询中返回一些数据。

在 GraphQL 中有三个主要概念:

  1. 查询(queries) - 从服务器获取数据
  2. 突变(mutations) - 修改服务器上的数据并获取更新数据(建立,更新,删除)
  3. 订阅(subscriptions) - 与服务器保持实时链接

这三个主要概念我会一一解释。

Queries

简单来讲,GraphQL 中的查询就是获取数据的方式。GraphQL 中的查询会得到所需的确切数据。很少也很多。这对咱们的 API 产生了巨大的积极影响 - 再也不像咱们使用 REST API 那样过分获取或提取不足信息。

让咱们来中建立一个查询类型,首先,在 schema.graphql中添加一个名为 Query 的新类型:

type Query {
  users: [User!]!
}
复制代码

users 查询将返回给咱们一个或多个用户的数组。它不会返回 null,由于咱们在后面加了 ! ,这意味着它是一个不可为空的查询,应该老是返回一些东西。

既然能返回多个,咱们也能返回一个特定用户,在 Query 类型中添加一个新的查询 user:

type Query {
    users: [User!]!
+   user(id: ID!): User!
  }
复制代码

你会发现查询可以传递参数,查询特定用户的时候把用户的 id 做为参数传入。

那么 GraphQL 如何知道去哪获取到数据返回呢?这就是 resolvers.js 的做用,它会告诉 GraphQL 如何以及在何处获取数据。

打开 resolvers.js 文件,更改一下代码:

import { users } from "./db"

const resolvers = {
  Query: {
    user: (parent, { id }, context, info) => {
      return users.find(user => user.id === id)
    },
    users: (parent, args, context, info) => {
      return users
    }
  }
}

export default resolvers
复制代码

解释一下以上代码是如何工做的:

  • 每一个查询解析器都有四个参数。在 user 函数中,咱们将 id 做为参数传递,而后返回与传递的 id 匹配的特定用户
  • users 函数中,咱们只是返回已存在的 users 数组,它会返回全部的用户

如今,咱们将测试咱们的查询是否正常工做。浏览器打开 localhost:4000,在左边输入如下代码而后点运行按钮:

query {
  users {
    id
    name
    email
    age
  }
}
复制代码

试试返回 id 为 1 的用户:

query {
  user(id: 1) {
    id
    name
    email
    age
  }
}
复制代码

Mutations

在 GraphQL 中,Mutations 是修改服务器上的数据并获取更新数据的方式。你能够理解为相似 REST 的CUD(CREATE,UPDATE,DELETE)。

咱们来建立一个类型突变,咱们全部的突变都将在这种类型中结束。在 schema.graphql 文件中编写一个名为 mutation 的新类型:

type Mutation {
  createUser(id: ID!, name: String!, email: String!, age: Int): User!
  updateUser(id: ID!, name: String, email: String, age: Int): User!
  deleteUser(id: ID!): User!
}
复制代码

上述代码建立了三个 Mutation:

  1. createUser - 咱们传入的参数 idnameemailage,应该返回一个新的用户
  2. updateUser - 传入 id 和新的 nameemailage, 应该返回一个更新后的用户
  3. deleteUser - 传入 id ,应该返回被删除掉用户的信息

如今,咱们去 resolvers.js 文件中,在 Query 对象下方插入一个新的 Mutation 对象。

Mutation: {
    createUser: (parent, { id, name, email, age }, context, info) => {
      const newUser = { id, name, email, age }
      users.push(newUser)
      return newUser
    },
    updateUser: (parent, { id, name, email, age }, context, info) => {
      let newUser = users.find(user => user.id === id)
      newUser.name = name
      newUser.email = email
      newUser.age = age
      return newUser
    },
    deleteUser: (parent, { id }, context, info) => {
      const userIndex = users.findIndex(user => user.id === id)
      if (userIndex === -1) throw new Error("User not found.")
      const deletedUsers = users.splice(userIndex, 1)
      return deletedUsers[0]
    }
  }
复制代码

该去 localhost:4000 看看咱们写的 Mutations 是否有效了,在页面上输入:

mutation {
  createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) {
    id
    name
    email
    age
  }
}
复制代码

你也能够尝试一下其余的 Mutation。

Subscriptions

正如我以前所说,Subscriptions (订阅)是你与服务器保持实时链接的方式。这意味着不管什么时候在服务器中发生事件,而且每当调用该事件时,服务器都会将相应的数据发送到客户端。经过使用订阅,你能够将应用程序更新为不一样用户之间的最新更改。

最基本的订阅示例:

subscription {
  users {
    id
    name
    email
    age
  }
}
复制代码

你会说它与查询很是类似,但它的工做方式和查询不一样。当服务器中的某些内容更新时,服务器将运行订阅中指定的 GraphQL 查询,并将更新的结果发送到客户端。我并不打算在这篇文章中使用订阅,但若是你想了解更多关于它们的信息,请点击此处

总结

如你所见,GraphQL 是一项很是强大的新技术。它为咱们提供了构建更好和精心设计的 API 的真正能力。这就是为何我建议你如今开始学习它。

对我来讲,它最终将取代 REST。

感谢阅读文章,请在下面发表评论!