作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Amaury米
验证专家 在工程
12 的经验

Amaury的硕士/硕士学位告诉他在web和移动(Node)的全栈工作.js, 反应, 反应 Native)以及区块链应用程序开发.

专业知识

共享

您可能听说过这个领域的新成员:GraphQL. 如果没有,GraphQL就是一种新的获取方式 api, 休息的替代方案. 它最初是Facebook的一个内部项目,由于它是开源的,它已经获得了收益 牵引力很大.

本文的目的是帮助您轻松地从休息过渡到GraphQL, 无论您是已经决定使用GraphQL,还是只是想尝试一下. 不需要预先了解GraphQL, 但是需要对休息 api有一定的了解才能理解本文.

GraphQL vs. 休息 -一个GraphQL教程

本文的第一部分将首先给出我个人认为GraphQL优于休息的三个原因. 第二部分是关于如何在后端添加GraphQL端点的教程.

GraphQL vs. 休息:为什么放弃休息?

如果您仍在犹豫GraphQL是否适合您的需求, 对“休息 vs . 休息”的相当广泛和客观的概述. GraphQL”给出 在这里. 然而,关于我使用GraphQL的三大理由,请继续阅读.

原因1:网络性能

假设您在后端有一个用户资源,其中包含名、姓、电子邮件和其他10个字段. 在客户机上,通常只需要其中的两个.

的休息调用 /用户 端点返回用户的所有字段,客户机只使用它需要的字段. 显然存在一些数据传输浪费,这可能是移动客户端需要考虑的问题.

GraphQL默认获取尽可能小的数据. 如果只需要用户的姓和名,可以在查询中指定.

下面的接口称为graphhiql,它类似于GraphQL的API资源管理器. 为了本文的目的,我创建了一个小项目. 代码是托管的 GitHub上,我们将在第二部分深入探讨.

在界面的左侧窗格中是查询. 这里,我们正在获取所有用户 得到 /用户 使用休息,并且只获取他们的姓和名.

查询

查询{
  用户{
    first名字
    姓
  }
}

结果

{
  "数据":{
    “用户”:(
      {
        “first名字”:“约翰”,
        “姓”:“母鹿”
      },
      {
        “first名字”:“艾丽西亚”,
        “姓”:“史密斯”
      }
    ]
  }
}

如果我们也想收到电子邮件,在“姓氏”下面加一个“email”行就可以了.

一些休息后端确实提供了如下选项 /用户?字段= first名字、姓 返回部分资源. 不管怎样, 谷歌推荐. 然而, 默认情况下不实现, 这使得请求几乎不可读, 特别是当您输入其他查询参数时:

  • &状态=活跃 过滤活跃用户
  • &Types= createdAat 按用户的创建日期对其进行排序
  • &sortDirection = desc 因为你显然需要它
  • &包括=项目 以包含用户的项目

这些查询参数是添加到休息 API以模仿查询语言的补丁. GraphQL首先是一种查询语言,它从一开始就使请求简洁而精确.

原因2:“包含vs .. “终点”设计选择

假设我们想要构建一个简单的项目管理工具. 我们有三种资源:用户、项目和任务. 我们还定义了资源之间的以下关系:

资源之间的关系

以下是我们向世界展示的一些端点:

端点描述
得到 /用户列出所有用户
/用户/:id获取id:id的单个用户
/用户/:id /项目获取一个用户的所有项目

端点简单、易读且组织良好.

当我们的请求变得更复杂时,事情会变得更棘手. 让我们来看看 /用户/:id /项目 端点:假设我只想在主页上显示项目的标题, 但是仪表板上的项目+任务, 无需进行多个休息调用. 我会说:

  • /用户/:id /项目 作为首页.
  • /用户/:id /项目?包括=任务 (例如)在仪表板页面上,以便后端追加所有相关任务.

通常的做法是添加查询参数 ?包括=... 要做到这一点,甚至是推荐的 JSON API 规范. 查询参数如下 ?包括=任务 仍然可读,但不久之后,我们将结束 ?包括=任务,任务.老板的任务.评论,任务.评论.作者.

在这种情况下,创建一个 /项目 端点来完成此操作? 类似的 /项目?用户id =: id&包括=任务,因为我们可以少包括一个层次的关系? 实际上是a /任务?用户id =: id 端点也可以工作. 这可能是一个困难的设计选择, 更复杂的是 如果我们有一个多对多关系.

GraphQL使用 包括 方法无处不在. 这使得获取关系的语法功能强大且一致.

下面是一个从id为1的用户获取所有项目和任务的示例.

查询

{
  用户(id: 1) {
    项目{
      名字
      任务{
        描述
      }
    }
  }
}

结果

{
  "数据":{
    "用户":{
      “项目”:[
        {
          "名字": "从休息迁移到GraphQL",
          “任务”:[
            {
              "描述": "Read tutorial"
            },
            {
              "描述": "开始编码"
            }
          ]
        },
        {
          名字:创建博客;
          “任务”:[
            {
              “描述”:“写文章草稿”
            },
            {
              描述:“建立博客平台”
            }
          ]
        }
      ]
    }
  }
}

如您所见,查询语法很容易阅读. 如果我们想要更深入,包括任务, 评论, 图片, 和作者, 我们不会再考虑如何组织我们的API. GraphQL使获取复杂对象变得容易.

原因3:管理不同Types的客户

在构建后端时, 我们总是从尝试让API尽可能地被所有客户端广泛使用开始. 然而,客户总是希望少调用,多获取. 有很深的包括, 部分资源, 和过滤, web和移动客户端发出的请求可能会有很大的不同.

对于休息,有两个解决方案. 我们可以创建一个自定义端点(i.e.,别名端点,e.g., / mobile_user)、自定义表示(内容Types:应用程序/盾.休息-应用程序-example.com + v1 +移动+ json),甚至是特定于客户端的API(比如 Netflix曾经这样做过). 这三种方法都需要后端开发团队付出额外的努力.

GraphQL为客户端提供了更多的功能. 如果客户端需要复杂的请求,它将自己构建相应的查询. 每个客户机可以以不同的方式使用相同的API.

如何开始使用GraphQL

在大多数关于“GraphQL vs . sql”的争论中. 今天,人们认为他们必须在两者中任选其一. 这是不正确的.

现代应用程序通常使用几种不同的服务,这些服务公开了几种api. 实际上,我们可以将GraphQL看作所有这些服务的网关或包装器. 所有客户机都将访问GraphQL端点, 这个端点会到达数据库层, 像Elastic搜索或Sendgrid这样的外部服务, 或其他休息端点.

GraphQL与. 休息端点

使用两者的第二种方法是有一个单独的 / graphql 端点上的休息 API. 如果已经有许多客户端访问您的休息 API,这一点尤其有用, 但您希望在不损害现有基础设施的情况下尝试GraphQL. 这就是我们今天要探讨的解决方案.

如前所述,我将使用一个可用的小示例项目来演示本教程 GitHub上. 它是一个简化的项目管理工具,包含用户、项目和任务.

这个项目使用的技术是Node.web服务器采用SQLite和Express,关系数据库采用SQLite, ORM采用Sequelize. 中定义了三个模型——用户、项目和任务 模型 文件夹. 休息端点 / api /用户*, / api /项目*和 / api /任务*暴露在世界上,并定义在 休息 文件夹.

* 注意:在发布后,Heroku停止提供免费托管,并且演示不再可用.

请注意,GraphQL可以安装在任何Types的后端和数据库上, 使用任何编程语言. 这里使用的技术是为了简单和可读性.

我们的目标是创造一个 / graphql 端点,而不删除休息端点. GraphQL端点将直接访问数据库ORM以获取数据, 这样它就完全独立于休息逻辑.

Types

数据模型在GraphQL中表示为 Types,它们是强Types的. 在您的模型和GraphQLTypes之间应该有1对1的映射. 我们的 用户 Types是:

Types用户{
  id: id! # The”!意思是必需的
  first名字:字符串
  姓:字符串
  电子邮件:字符串
  Project: [Project] # Project是另一种GraphQLTypes
}

查询

查询 定义可以在GraphQL API上运行的查询. 按照惯例,应该有 Root查询,其中包含所有现有查询. 我还指出了每个查询的休息等效:

TypesRoot查询 {
  user(id: id): user #对应得到 / api /用户/:id
  用户(用户): #对应得到 / api /用户
  项目(id: id!):项目 #对应得到 / api /项目/:id
  项目: [Project] #对应得到 / api /项目
  任务(id: id!):任务 #对应得到 / api /任务/:id
  tasks: [Task] #对应得到 / api /任务
}

Mutations

如果查询是 得到 请求, Mutations 可以看作是 帖子/补丁//删除 请求(尽管实际上它们是查询的同步版本).

按照惯例,我们把所有的Mutations放在a里 RootMutation:

TypesRootMutation {
  create用户(输入:用户Input!): 用户 #对应帖子 / api /用户
  update用户 (id: id!, input: 用户Input!): 用户 #对应补丁 / api /用户
  remove用户 (id: id!): 用户 #对应于删除 / api /用户

  createProject(输入:ProjectInput!):项目
  updateProject (id: id!,输入:ProjectInput!):项目
  从(id: id!):项目
  
  createTask(输入:TaskInput!):任务
  updateTask (id: id!,输入:taskput!):任务
  removeTask (id: id!):任务
}

注意,我们在这里引入了新的Types,称为 用户Input, ProjectInput, TaskInput. 这也是休息的一种常见做法, 创建用于创建和更新资源的输入数据模型. 在这里,我们 用户Input Types是我们的 用户 键入不带 id项目 字段,并注意关键字 input 而不是 Types:

输入用户Input {
  first名字:字符串
  姓:字符串
  电子邮件:字符串
}

模式

通过Types、查询和Mutations,我们定义了 GraphQL模式,这是GraphQL端点向世界公开的内容:

模式{
  查询:Root查询
  变异:RootMutation
}

这个模式是强Types的,它允许我们在graphhiql *中使用那些方便的自动补全.

* 注:出版后, Heroku停止提供免费托管服务, 本文的演示不再可用.

解析器

现在我们有了公共模式, 现在是时候告诉GraphQL在请求这些查询/Mutations时该做什么了. 解析器 do the hard work; they can, for example:

  • 击中一个内部休息端点
  • 调用微服务
  • 点击数据库层执行CRUD操作

我们在示例应用程序中选择第三个选项. 让我们看看我们的 解析器文件:

Const 模型 = sequelize.模型;

Root查询: {
  用户(根,{id},上下文){
    回归模型.用户.findById (id、上下文);
  },
  用户s (root, args, context) {
    回归模型.用户.findAll({}、上下文);
  },
  //项目和任务的解析器在这里
},
    
提醒一下,我们的Root查询Types是:
TypesRoot查询 {
  user(id: id):用户
  用户(用户):
 
  #其他查询
}

这意味着,如果 用户(id: id!) 在GraphQL上请求查询,然后返回 用户.findById (),它是一个Sequelize ORM函数,从数据库中获取.

在请求中加入其他模型怎么样? 我们需要定义更多的解析器:

用户:{
  项目(用户){
    返回用户.get项目(); // get项目 is a function managed by Sequelize ORM
  }
},
    
提醒一下,我们的用户Types是:
Types用户{
  我们在上面为这个字段定义了一个解析器
  # ...其他领域
}
*/

所以当我们请求 项目 字段中 用户 在GraphQL中输入,此连接将追加到数据库查询.

最后是Mutations解析器:

RootMutation: {
  create用户 (root, {input}, context) {
    回归模型.用户.创建(输入、上下文);    
  },
  update用户 (root, {id, input}, context) {
    回归模型.用户.更新(输入,{ ...上下文,其中:{id}});
  },
  remove用户 (root, {id}, context) {
    回归模型.用户.破坏(输入,{ ...上下文,其中:{id}});
  },
  // ... 项目和任务的解析器在这里
}

你可以在这里摆弄一下. 为了保持服务器上的数据干净, 我禁用了Mutations的解析器, 也就是说Mutations不会产生任何作用, 数据库中的更新或删除操作(因此返回 在界面上).

查询

查询get用户With项目 {
  用户(id: 2) {
    first名字
    姓
    项目{
      名字
      任务{
        描述
      }
    }
  }
}

createProject {
  createProject(input: {名字: "New Project", 用户Id: 2}) {
    id
    名字
  }
}

结果

{
  "数据":{
    "用户":{
      “first名字”:“艾丽西亚”,
      “姓”:“史密斯”,
      “项目”:[
        {
          "名字": "Email 市场营销 Campaign";
          “任务”:[
            {
              "描述": "获取用户列表"
            },
            {
              描述:写邮件模板
            }
          ]
        },
        {
          “名字”:“Hire new developer”,
          “任务”:[
            {
              “描述”:“寻找候选人”
            },
            {
              “描述”:“准备面试”
            }
          ]
        }
      ]
    }
  }
}

为现有应用重写所有Types、查询和解析器可能需要一些时间. 然而,有很多工具可以帮助您. 例如, 在那里 工具 将SQL模式转换为GraphQL模式,包括解析器!

把所有东西放在一起

有了定义良好的模式和解析器,就可以在模式的每个查询上执行操作 / graphql 后端端点:

//挂载GraphQL到/ GraphQL
const schema = makeExecutable模式({
  Typesdef, //我们的Root查询和RootMutation模式
  resolvers: resolvers() //我们的解析器
});
应用程序.use('/ graphql', graphqlExpress({schema}));

我们可以在后端拥有一个漂亮的graphhiql界面*. 要在不使用graphhiql的情况下发出请求,只需复制请求的URL (1).e., http://host/ graphql?查询=查询7 b % 0 a % % 20% 20% 20用户3 (id % % 202) % 20% 7 b % 0 a % 20 first名字 % 0 a % 20% 20% 20% 20% 20% 20% 20 姓 % 0 a % 20% 20% 20% 7 b % 0 a % 20项目% 20% 20% 20% 20% 20% 20% 20名% 0 a % 20% 20% 20% 20% 20% 20任务7 b % 0 a % % 20% 20% 20% 20% 20% 20% 20% 20% 20描述% 0 a % 20% 20% 20% 20% 20% 20% 7 d % 0 a % 20% 20% 20% 20% 7 d % 0 a % 20% 20% 7 d % 0 a % 7 d*),并使用cURL、AJAX或直接在浏览器中运行它. 当然,有一些GraphQL客户端可以帮助您构建这些查询. 请看下面的一些例子.

* 注意:在发布后,Heroku停止提供免费托管,并且演示不再可用.

接下来是什么?

本文的目的是让您体验一下GraphQL的样子,并向您展示在不抛弃休息基础设施的情况下完全可以尝试GraphQL. 了解GraphQL是否适合您的需求的最佳方法是亲自尝试. 我希望这篇文章能让你尝试一下.

有很多特性我们在本文中没有讨论, 比如实时更新, 服务器端批处理, 身份验证, 授权, 客户端缓存, 文件上传, 等. 了解这些特性的一个很好的资源是 如何制作图形.

以下是其他一些有用的资源:

服务器端工具描述
graphql-jsGraphQL的参考实现. 你可以用它 express-graphql 要创建一个服务器.
graphql-server创建的一体化GraphQL服务器 阿波罗的团队.
其他平台的实现Ruby, PHP等.
客户端工具描述
继电器一个连接反应和GraphQL的框架.
apollo-client.带有绑定的GraphQL客户端 反应, 角2, 其他前端框架.

总之,我相信GraphQL不仅仅是炒作. 它不会在明天就取代休息, 但它确实为一个真正的问题提供了一个高效的解决方案. 这是相对较新的, 最佳实践仍在发展中, 但这绝对是一项我们将在未来几年听到的技术.

关于总博客的进一步阅读:

了解基本知识

  • 什么是GraphQL?

    GraphQL是一种查询语言,是休息的替代方案. 它最初是Facebook的一个内部项目.

  • GraphQL与休息有什么不同?

    GraphQL将所有休息ful端点合并为一个,并使用更少的网络流量.

聘请Toptal这方面的专家.
现在雇佣
Amaury米

Amaury米

验证专家 在工程
12 的经验

法国巴黎

2017年3月15日成为会员

作者简介

Amaury的硕士/硕士学位告诉他在web和移动(Node)的全栈工作.js, 反应, 反应 Native)以及区块链应用程序开发.

作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 隐私政策.

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 隐私政策.

Toptal开发者

加入总冠军® 社区.