内容简介:当谈到客户端和应用程序服务器之间的网络请求时,REST(*表现层状态转换*的代表)是连接二者最常用的选择之一。在REST API 的世界中,一切都围绕着如何把资源作为可访问的 URL。然后我们会进行 CURD 操作(新建、读取、更新、删除),这些操作是 HTTP 的基本方法,如 GET、POST、PUT 和 DELETE,来与数据进行交互。这是一个典型的 REST 请求的例子:REST API 的响应格式未必会是 JSON,但是这是目前大多数 API 的首选方法。
当谈到客户端和应用程序服务器之间的网络请求时,REST(*表现层状态转换*的代表)是连接二者最常用的选择之一。在REST API 的世界中,一切都围绕着如何把资源作为可访问的 URL。然后我们会进行 CURD 操作(新建、读取、更新、删除),这些操作是 HTTP 的基本方法,如 GET、POST、PUT 和 DELETE,来与数据进行交互。
这是一个典型的 REST 请求的例子:
// 请求示例 https://swapi.co/api/people/ // 上面请求的 JSON 格式响应 { "results": [ { "name": "Luke Skywalker", "gender": "male", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/", "https://swapi.co/api/films/7/" ], } { "name": "C-3PO", "gender": "n/a", "homeworld": "https://swapi.co/api/planets/1/", "films": [ "https://swapi.co/api/films/2/", "https://swapi.co/api/films/5/", "https://swapi.co/api/films/4/", "https://swapi.co/api/films/6/", "https://swapi.co/api/films/3/", "https://swapi.co/api/films/1/" ], } ] } 复制代码
REST API 的响应格式未必会是 JSON,但是这是目前大多数 API 的首选方法。 除了 REST,还出现了另一种处理网络请求的方法:GraphQL。它于2015年开源,正在改变着开发人员在服务器端编写API以及在客户端处理API的方式。 并由 Facebook 开发并积极维护。
REST 的弊端
GraphQL 是一种用于开发 API 的查询语言。和 REST(一种架构或者“一种做事方式”)相比,GraphQL 的开发基于一个理念:客户端每次仅从服务端请求所需要的项目集合。
在上面的例子中,使用了 REST 或者其他类似架构。我们请求 Star Wars 系列电影中 Luke Skywalker 出现过的电影时,我们得到了一系列的 电影
或者 homeworld
的名称,他们还包含了不同的 API URL,引导我们去了解不同 JSON 数据集的详细信息。这肯定是一个过度获取(over fetching)的例子。客户端为了去获取人物 Luke Skywalker 出现在电影中的详情以及他家乡星球的名称,只能去向服务端发起多个请求。
使用 GraphQL,就可以将其解析为单个网络请求。转到 API 网址: https://graphql.github.io/swapi-graphql/
,查看运行以下查询(query)看看。
注意:在下面的例子中,你可以不必理会 GraphQL API 幕后的工作方式。我将在本教程后面逐步构建你自己的(可能是第一个)GraphQL API。
{ allPeople { edges { node { name gender homeworld { name } filmConnection { edges { node { title } } } } } } } 复制代码
我们将获取我们需要的数据。例如角色的名称、他们的性别( gender
)、家园( homeworld
),以及他们出现的电影( films
)的标题。运行上述查询,你将获得以下结果:
{ "data": { "allPeople": { "edges": [ { "node": { "name": "Luke Skywalker", "gender": "male", "homeworld": { "name": "Tatooine" }, "filmConnection": { "edges": [ { "node": { "title": "A New Hope" } }, { "node": { "title": "The Empire Strikes Back" } }, { "node": { "title": "Return of the Jedi" } }, { "node": { "title": "Revenge of the Sith" } }, { "node": { "title": "The Force Awakens" } } ] } } }, { "node": { "name": "C-3PO", "gender": "n/a", "homeworld": { "name": "Tatooine" }, "filmConnection": { "edges": [ { "node": { "title": "A New Hope" } }, { "node": { "title": "The Empire Strikes Back" } }, { "node": { "title": "Return of the Jedi" } }, { "node": { "title": "The Phantom Menace" } }, { "node": { "title": "Attack of the Clones" } }, { "node": { "title": "Revenge of the Sith" } } ] } } } ] } } } 复制代码
如果应用程序的客户端正在触发上述 GraphQL URL,它只需要在网络上发一个请求就可以得到所需结果。从而消除了任何会导致过度获取或发送多个请求的可能性。
先决条件
要学习本课程,你只需要在本地计算机上安装 nodejs
和 npm
即可。
- Nodejs
^8.12.0
- npm
^6.4.1
GraphQL 简述
简而言之, GraphQL 是一种用于阐述如何请求 data 的语法,通常用于从客户端检索数据(也称为 query )或者对其进行更改(也称为 mutation )。
GraphQL 几乎没有什么定义特征:
- 它允许客户端准确指定所需的数据。这也称为声明性数据提取。
- 对网络层没有特殊要求
- 更容易组合来自多个源的数据
- 在以 schema 和 query 的形式声明数据结构时,它使用强类型系统。这有助于在发送网络请求之前校验查询。
GraphQL API 的构建模块
GraphQL API 有四个构建模块:
- schema
- query
- mutations
- resolvers
Schema以对象的形式在服务器上定义。每个对象对应于数据类型,以便于去查询他们。例如:
type User { id: ID! name: String age: Int } 复制代码
上面的 schema 定义了一个用户对象的样子。其中必需的字段 id
用 !
符号标识。还包含其他字段,例如 string 类型的 name
和 integer 类型的 age
。这也会在查询数据的时候对 schema
进行验证。
Queries是你用来向 GraphQL API 发出请求的方法。例如,在我们上面的示例中,就像我们获取 Star Wars 相关的数据时那样。让我们简化一下,如果在 GraphQL 中查询,就是在查询对象的特定字段。例如,使用上面相同的 API,我们能获取 Star Wars 中所有角色的名称。下面你可以看到差异,在图片的左侧是查询,右侧是结果。(译者注: 原文是 on the right-hand side is the image,译者认为不是很合适)
使用 GraphQL 查询的好处是它们可以嵌套到你想要的深度。这在 REST API 中很难做到。(在 REST API 中)操作变得复杂得多。
下面是一个更复杂的嵌套查询示例:
Mutations:在 REST 架构中,要修改数据,我们要么使用 POST
来添加数据,要么使用 PUT
来更新现有字段的数据。在 GraphQL 中,整体的概念是类似的。你可以发送一个 query 来在服务端执行写入操作。但是。这种形式的查询称为 Mutation。
Resolvers是 schema 和 data 之间的纽带。它们提供可用于通过不同操作与数据库交互的功能。
在这个教程中,你将学习用我们刚刚学到的构件,来使用 Nodejs 构建 GraphQL 服务器。
Hello World! 使用 GraphQL
现在我们来写我们第一个 GraphQL 服务器。本教程中,我们将使用Apollo Server。我们需要为 Apollo Server 安装三个包才能使用现有的 Express 应用程序作为中间件。Apollo Server 的优点在于它可以与 Node.js 的几个流行框架一起使用:Express、Koa 和Hapi。Apollo 本身和库无关,因此在客户端和服务器应用程序中,它可以和许多第三方库连接。
打开你的终端安装以下依赖:
# 首先新建一个空文件夹 mkdir apollo-express-demo # 然后初始化 npm init -y # 安装需要的依赖 npm install --save graphql apollo-server-express express 复制代码
让我们简要了解下这些依赖的作用。
graphql apollp-server-express express
你可以在下面的图中看到我安装了全部的依赖,没有出现任何错误。
在你项目的根路径下,新建一个名字为 index.js
、包含以下代码的文件。
const express = require('express'); const { ApolloServer, gql } = require('apollo-server-express'); const typeDefs = gql` type Query { hello: String } `; const resolvers = { Query: { hello: () => 'Hello world!' } }; const server = new ApolloServer({ typeDefs, resolvers }); const app = express(); server.applyMiddleware({ app }); app.listen({ port: 4000 }, () => console.log(`:rocket: Server ready at http://localhost:4000${server.graphqlPath}`) ); 复制代码
这是我们服务器文件的起点。开始我们仅仅只需要 express
模块。 gql
是一个模板文字标记,用于将 GraphQL schema 编写为类型。schema 由类型定义组成,并且强制包含一个用于读取数据的 Query 类型,用于读取数据。它还可以包含表示其他数据字段的字段和嵌套字段。在我们上面的例子中,我们定义了 typeDefs
来编写 graphQL 的 schema。
然后 resolvers
映入眼帘。Resolver 用于从 schema 中返回字段的数据。在我们的示例中,我们定义了一个 resolver,它将函数 hello()
映射到我们的 schema 上的实现。接下来,我们创建一个 server
,它使用 ApolloServer
类来实例化并启动服务器。由于我们使用了 Express,所以我们需要集成 ApolloServer
类。通过 applyMiddleware()
作为 app
来传递它,来添加 Apollo Server 的中间件。这里的 app
是 Express 的一个实例,代表了现有的应用程序。
最后,我们使用 Express 模块提供的 app.listen()
来引导服务器。要运行服务器,只需要打开 terminal 并运行命令 node index.js
。现在,从浏览器窗口访问 url: http://localhost:4000/graphql
来看看它的操作。
Apollo Server 为你设置了 GraphQL Playground,供你快速开始运行 query,探索 schema,如下所示。
要运行一个 query,在左侧编辑空白部分,输入以下 query。然后按中间的 ▶ (play)按钮。
右侧的 schema 卡描述了我们查询 hello
的数据类型。这直接来自我们服务器中定义的 typeDefs
。
*瞧!*你刚创建了第一个 GraphQL 服务器。现在让我们拓展下我们对现实世界的认知。
使用 GraphQL 构建 API
目前为止我们整理了所有必要的模块以及随附的必要术语。在这一节,我们将用 Apollo Server 为我们的演示去创建一个小的 Star Wars API 。你可能已经猜到了 Apollo server 是一个库,可以帮助你使用 Nodejs 将 GraphQL schema 连接到 HTTP server。它不局限于特定的 Node 框架。例如上一节中我们使用了 ExpressJS。Apollo Server 支持Koa,Restify,Hapi 和 Lambda。对于我们的 API,我们继续使用 Express。
使用 Babel 进行编译
如果想从头开始,请继续。从 Hello World!With GraphQL
一节安装所有的库。这是我们在前面一节中安装的所有依赖:
"dependencies": { "apollo-server-express": "^2.1.0", "express": "^4.16.4", "graphql": "^14.0.2" } 复制代码
我将使用相同的项目和相同的文件 index.js
去引导服务器启动。但是在我们构建我们的 API 之前,我想告诉你如何在我们的演示项目中使用 ES6 modules。对于使用像 React 和 Angular 这样的前端库,他们已经支持了 ES6 特性。例如 import
和 export default
这样的语句。Nodejs 版本 8.x.x
解决了这个问题。我们所需要的只是一个转换器(transpiler)让我们使用 ES6 特性编写 JavaScript。你完全可以跳过这个步骤使用旧的 require()
语句。
那么什么是 转换器 呢?
转换器(Transpiler)也被称作‘源到源的编译器’,从一种编程语言写的源码中读取代码转换成另一种语言的等效代码。
在 Nodejs 的情况下,我们不会切换编程语言,而是要使用哪些我目前使用的 LTS 版本的 Node 不支持的语言的新特性。我将安装 Babel 编译器 ,并通过接下来的配置过程在我们的项目中启用它。
首先,你需要安装一些依赖,记得使用 -D
参数。因为我们只会在开发环境中用到这些依赖。
npm install -D babel-cli babel-preset-env babel-watch 复制代码
只要你成功安装了他们,在项目的根目录下添加一个 .babelrc
文件并且添加以下配置:
{ "presets": [env] } 复制代码
配置流程的最后一步是在 package.json
中添加一个 dev
脚本(script)
。一旦(项目文件)发生变化,babel 编译器将自动运行。这由 babel-watch
完成。同时它也负责重新启动Nodejs 网络服务器。
"scripts": { "dev": "babel-watch index.js" } 复制代码
要查看它的操作,请将以下代码添加到 index.js
中,看看是否一切正常。
import express from 'express'; const app = express(); app.get('/', (req, res) => res.send('Babel Working!')); app.listen({ port: 4000 }, () => console.log(`:rocket: Server ready at http://localhost:4000`) ); 复制代码
在终端中输入 npm run dev
,不出意外,你可以看到下面的信息:
你也可以在浏览器中访问 http://localhost:4000/
去看看其操作。
添加 Schema
我们需要一个 schema 来启动我们的 GraphQL API。让我们在 api
目录下创建一个名字为 api/schema.js
的新文件。添加以下 schema。
import { gql } from 'apollo-server-express'; const typeDefs = gql` type Person { id: Int name: String gender: String homeworld: String } type Query { allPeople: [Person] person(id: Int!): Person } `; export default typeDefs; 复制代码
我们的 schema 一共包含两个 query。第一个是 allPeople
,通过它我们可以列出到 API 中的所有的人物。第二个查询 person
是使用他们的 id 检索一个人。这两种查询类型都依赖于一个名为 Person
对象的自定义类型,该对象包含四个属性。
添加 Resolver
我们已经了解了 resolver 的重要性。它基于一种简单的机制,去关联 schema 和 data。Resolver 是包含 query 或者 mutation 背后的逻辑和函数。然后使用它们来检索数据并在相关请求上返回。
如果在使用 Express 之前构建了服务器,则可以将 resolver 视为控制器,其中每一个控制器都是针对特定路由构建。由于我们不在服务器后面使用数据库,因此我们必须提供一些虚拟数据来模拟我们的 API。
创建一个名为 resolvers.js
的新文件并添加下面的文件。
const defaultData = [ { id: 1, name: 'Luke SkyWaler', gender: 'male', homeworld: 'Tattoine' }, { id: 2, name: 'C-3PO', gender: 'bot', homeworld: 'Tattoine' } ]; const resolvers = { Query: { allPeople: () => { return defaultData; }, person: (root, { id }) => { return defaultData.filter(character => { return (character.id = id); })[0]; } } }; export default resolvers; 复制代码
首先,我们定义 defaultData
数组,其中包含 Star Wars 中两个人物的详细信息。根据我们的 schema ,数组中的这两个对象都有四个属性。接下来是我们的 resolvers
对象,它包含两个函数。这里可以使用 allPeople()
来检索 defaultData
数组中的所有数据。 person()
箭头函数使用参数 id
来检索具有请求 ID 的 person 对象。这个已经在我们的查询中定义了。
你必须导出 resolver 和 schema 对象才能将它们与 Apollo Server 中间件一起使用。
实现服务器
现在我们定义了 schema 和 resolver,我们将要在 index.js
文件里边实现服务器。首先从 apollo-server-express
导入 Apollo-Server。我们还需要从 api/
文件夹导入我们的 schema 和 resolvers 对象。然后,使用 Apollo Server Express 库中的 GraphQL 中间件实例化 GraphQL API。
import express from 'express'; import { ApolloServer } from 'apollo-server-express'; import typeDefs from './api/schema'; import resolvers from './api/resolvers'; const app = express(); const PORT = 4000; const SERVER = new ApolloServer({ typeDefs, resolvers }); SERVER.applyMiddleware({ app }); app.listen(PORT, () => console.log(`:rocket: GraphQL playground is running at http://localhost:4000`) ); 复制代码
最后,我们使用 app.listen()
来引导我们的 Express 服务器。你现在可以从终端执行命令 npm run dev
来运行服务器。服务器节点启动后,将提示成功消息,指示服务器已经启动。
现在要测试我们的 GraphQL API,在浏览器窗口中跳转 http://localhost:4000/graphql
URL 并运行以下 query。
{ allPeople { id name gender homeworld } } 复制代码
点击 play 按钮,你将在右侧部分看到熟悉的结果,如下所示。
一切正常,因为我们的查询类型 allPeople
具有自定义的业务逻辑,可以使用 resolver 检索所有数据(在我们的例子中,我们在 resolvers.js
中作为数据提供的模拟数据)。要获取单个人物对象,请尝试运行类似的其他 query。请记住,必须提供 ID。
{ person(id: 1) { name homeworld } } 复制代码
运行上面的查询,在结果中,你可以获得得到的每个字段/属性的值以进行查询。你的结果将类似于以下内容。
完美!我相信你一定掌握了如何创建 GraphQL query 并运行它。Apollo Server 库功能很强大。它让我们能够编辑 playground。 假设我们要编辑 playground 的主题? 我们要做的就是在创建 ApolloServer
实例时提供一个选项,在我们的例子中是 SERVER
。
const SERVER = new ApolloServer({ typeDefs, resolvers, playground: { settings: { 'editor.theme': 'light' } } }); 复制代码
playground
属性有很多功能,例如定义 playground 的默认端点(endpoint)以更改主题。你甚至可以在生产模式启用 playground。更多配置项可以在Apollo Server 的官方文档中找到,[ 这里。 ]
更改主题后我们获取下面的结果。
结论
如果你一步一步完成教程,那么 祝贺你!:tada:
你已经学习了如何使用 Apollo 库配置 Express 服务器来设置您自己的 GraphQL API。Apollo Server 是一个开源项目,是为全栈应用程序创建 GraphQL API 的最稳定的解决方案之一。他还支持客户端开箱即用的 React、Vue、Angular、Meteor 和 Ember 以及使用 Swift 和 Java 的 Native 移动开发。有关这方面的更多信息可以在 这里 找到。
在此 Github 仓库中查看教程的完整代码 :point_down:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- SQLServer之创建链接服务器
- 创建局域网Git服务器
- Laravel创建服务器提供者实例
- Express教程01:创建服务器、配置路由
- 使用Go语言创建静态文件服务器
- weblogic 脚本创建Managed Server (受管服务器)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据库系统概念
(美)Abraham Silberschatz、(美)Henry F.Korth、(美)S.Sudarshan / 杨冬青、李红燕、唐世渭 / 机械工业出版社 / 2012-3 / 99.00元
【编辑推荐】 数据库领域的殿堂级作品 夯实数据库理论基础,增强数据库技术内功的必备之选 对深入理解数据库,深入研究数据库,深入操作数据库都具有极强的指导作用! 【内容简介】 本书是数据库系统方面的经典教材之一,其内容由浅入深,既包含数据库系统基本概念,又反映数据库技术新进展。它被国际上许多著名大学所采用,包括斯坦福大学、耶鲁大学、得克萨斯大学、康奈尔大学、伊利诺伊大学......一起来看看 《数据库系统概念》 这本书的介绍吧!