作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
在 An Introduction to GraphQL中,您了解到 GraphQL 是一个开源查询语言和 API 运行时间,用于解决常见于传统 REST API 系统的问题。
开始了解所有 GraphQL 片段如何相匹配的一个好方法是创建一个 GraphQL API 服务器. 虽然 Apollo GraphQL是一个受众多大型公司喜爱的商业 GraphQL 实现,但它不是创建自己的 GraphQL API 服务器的先决条件。
在本教程中,您将创建一个 Express API 服务器在 Node.js中,为 GraphQL 终端提供服务。您还将基于 GraphQL 类型系统构建一个 GraphQL 方案,包括查询和突变等操作,以及解决函数来生成任何请求的响应。
前提条件
要遵循本教程,您将需要:
- 一个本地 Node.js 环境,您可以通过遵循 如何安装 Node.js 和创建本地开发环境为您的操作系统和分布程序的教程来设置
- 您可以在教程中找到的 GraphQL 的基本概念的理解, 如何引入 GraphQL。
- 熟悉 HTTP.
- 您可以从系列中获得的 HTML 和 JavaScript 的基本知识, 如何使用 HTML 构建网站 和 如何在 JavaScript 中编码.
设置 Express HTTP 服务器
第一步是设置 Express 服务器,您可以在写任何 GraphQL 代码之前完成。
在新项目中,您将安装express
和cors
并使用npm install
命令:
1npm install express cors
Express将是您的服务器的框架,它是 Node.js 的 Web 应用程序框架,旨在构建 API。 CORS包,即 Cross-Origin Resource Ssharing middleware,将允许您从浏览器轻松访问该服务器。
您还可以将 Nodemon 安装为 dev 依赖:
1npm install -D nodemon
Nodemon是帮助开发基于节点的应用程序的工具,通过在检测到目录中的文件更改时自动重新启动应用程序。
安装这些包将创建node_modules
和package.json
,列出了两个依赖和一个 dev 依赖。
使用nano
或您最喜欢的文本编辑器,打开package.json
进行编辑,这将看起来像这样:
1[label package.json]
2{
3 "dependencies": {
4 "cors": "^2.8.5",
5 "express": "^4.17.3"
6 },
7 "devDependencies": {
8 "nodemon": "^2.0.15"
9 }
10}
您将在此时将添加一些其他字段. 对 package.json
进行以下突出更改:
1[label package.json]
2{
3 "main": "server.js",
4 "scripts": {
5 "dev": "nodemon server.js"
6 },
7 "dependencies": {
8 "cors": "^2.8.5",
9 "express": "^4.17.3"
10 },
11 "devDependencies": {
12 "nodemon": "^2.0.15"
13 },
14 "type": "module"
15}
您将为服务器创建一个文件在server.js
,因此您将主
指向server.js
。
为了使在服务器上更容易开发,您还可以创建一个名为dev
的脚本,该脚本将运行nodemon server.js
。
最后,您添加模块
的类型
,以确保您可以在整个代码中使用导入
陈述,而不是使用默认的CommonJS要求
。
保存并关闭文件,当你完成。
接下来,创建一个名为server.js
的文件,在其中,你将创建一个简单的Express服务器,听到端口4000
,并发送一个请求,说你好,GraphQL!
。
1[label server.js]
2import express from 'express'
3import cors from 'cors'
4
5const app = express()
6const port = 4000
7
8app.use(cors())
9app.use(express.json())
10app.use(express.urlencoded({ extended: true }))
11
12app.get('/', (request, response) => {
13 response.send('Hello, GraphQL!')
14})
15
16app.listen(port, () => {
17 console.log(`Running a server at http://localhost:${port}`)
18})
此代码块创建了一个基本的 HTTP 服务器与 Express. 通过召唤 express
函数,你创建了一个 Express 应用程序. 设置了 CORS 和 JSON 的一些基本设置后,你将定义应该用GET
请求发送给 root (/
) 使用 app.get('/')。
保存并关闭文件,当你完成。
现在您可以运行命令来启动 Node 服务器:
1npm run dev
如果您在浏览器中访问http://localhost:4000
或运行curl http://localhost:4000
命令,您将看到它返回Hello, GraphQL!
表示Express服务器正在运行。
设置 GraphQL HTTP 服务器中间件
在本节中,您将开始将 GraphQL 架构集成到基本的 Express 服务器中,您将通过定义架构、解析器和连接到数据存储来做到这一点。
要开始将 GraphQL 集成到 Express 服务器中,您将安装三个包: graphql
、 express-graphql
和 @graphql-tools/schema
。
1npm install graphql@14 express-graphql @graphql-tools/schema
graphql
: 用于 GraphQL 的 JavaScript 引用实现express-graphql
: 用于 GraphQL 的 HTTP 服务器中间软件@graphql-tools/schema
: 一组用于更快的 GraphQL 开发的实用程序
您可以将这些包导入到「server.js」文件中,通过添加突出的行:
1[label server.js]
2import express from 'express'
3import cors from 'cors'
4import { graphqlHTTP } from 'express-graphql'
5import { makeExecutableSchema } from '@graphql-tools/schema'
6
7...
下一步是创建一个可执行的 GraphQL 方案。
为了避免设置数据库的负担,您可以使用内存存储器来查询 GraphQL 服务器将查询的数据。您可以创建一个具有数据库值的数据
对象。
1[label server.js]
2import express from 'express'
3import cors from 'cors'
4import { graphqlHTTP } from 'express-graphql'
5import { makeExecutableSchema } from '@graphql-tools/schema'
6
7const data = {
8 warriors: [
9 { id: '001', name: 'Jaime' },
10 { id: '002', name: 'Jorah' },
11 ],
12}
13
14...
这里的数据结构代表了一个名为战士
的数据库表,它有两个行,由Jaime
和Jorah
条目表示。
<$>[注]
**注:**使用真正的数据存储不在本教程的范围内。通过缩放器来访问和操纵 GraphQL 服务器中的数据。这可以通过手动连接到数据库,通过像 Prisma这样的 ORM来完成。 Asynchronous resolvers通过解决器的背景
来实现这一点。对于本教程的其余部分,我们将使用数据
变量来表示数据存储值
<$>
有了安装的包和一些数据,您现在将创建一个方案,通过描述可供查询的数据来定义API。
图形图表
现在你已经有了一些基本数据,你可以开始为API创建一个原始方案,以获得开始使用 GraphQL 终端所需的最小代码量. 这个方案旨在复制一些可以用于幻想角色扮演游戏的内容,其中有角色具有战士,魔法师和治愈者等角色。
一个 GraphQL 方案依赖于一个 类型系统。有一些内置类型,你也可以创建自己的类型. 对于这个示例,你将创建一个名为Warrior
的新类型
,并给它两个字段:id
和name
。
1type Warrior {
2 id: ID!
3 name: String!
4}
id
有ID
类型,而名称
有字符串
类型,这些都是内置的尺度或原始类型。
您所需要的唯一额外的信息是基本的Query
类型,这是 GraphQL 查询的入口点,我们将战士
定义为一系列的战士
类型。
1type Query {
2 warriors: [Warrior]
3}
有了这两种类型,你有一个有效的架构,可以在GraphQL HTTP中间软件中使用。最终,你在这里定义的架构将被转移到由graphql-tools
提供的makeExecutableSchema
函数中,作为typeDefs
。
typeDefs
:一个 GraphQL 架构语言字符串resolvers
:呼吁执行一个字段并产生值的函数
在server.js
中,导入依赖之后,创建一个typeDefs
变量,并将 GraphQL 方案分配为字符串,如下所示:
1[label server.js]
2...
3
4const data = {
5 warriors: [
6 { id: '001', name: 'Jaime' },
7 { id: '002', name: 'Jorah' },
8 ],
9}
10
11const typeDefs = `
12type Warrior {
13 id: ID!
14 name: String!
15}
16
17type Query {
18 warriors: [Warrior]
19}
20`
21
22...
现在你已经定义了你的数据集和方案,分别为数据
和typeDefs
。
GraphQL 解析器函数
Resolvers是为 GraphQL 服务器生成响应函数的集合,每个解决函数有四个参数:
obj
:这里不需要使用的母体对象,因为它已经是根或顶级对象args
:任何给该字段提供的 GraphQL 参数context
: 所有解析器之间共享的状态,通常是数据库连接info
: 附加信息。
在这种情况下,您将为根类型Query
创建解析器,并返回战士
的值。
要开始使用此示例服务器,请通过将突出的行添加到server.js
来传输本节中早些时候的内存数据库:
1[label server.js]
2...
3
4const typeDefs = `
5type Warrior {
6 id: ID!
7 name: String!
8}
9
10type Query {
11 warriors: [Warrior]
12}
13`
14
15const resolvers = {
16 Query: {
17 warriors: (obj, args, context, info) => context.warriors,
18 },
19}
20
21...
您现在已经添加了一个解决函数,称为战士
,将从背景
返回战士
。背景
是您的数据库输入点将被包含在那里,对于这个特定的实现,它将是包含您的内存数据库的数据
变量。
每个单独的解析函数有四个参数:obj、args、context、info. 目前我们方案中最有用的和最相关的参数是context,这是解析器共享的对象,常被用作GraphQL服务器与数据库之间的连接。
最后,随着typeDefs
和resolvers
的所有设置,您有足够的信息来创建一个可执行的方案。
1[label server.js]
2...
3
4const resolvers = {
5 Query: {
6 warriors: (obj, args, context, info) => context.warriors,
7 },
8}
9
10const executableSchema = makeExecutableSchema({
11 typeDefs,
12 resolvers,
13})
14
15...
makeExecutableSchema函数创建了一个完整的方案,您可以将其传输到 GraphQL 终端。
现在,将当前返回 Hello, GraphQL!
的默认根端点替换为以下 /graphql
端点,添加突出的行:
1[label server.js]
2...
3
4const executableSchema = makeExecutableSchema({
5 typeDefs,
6 resolvers,
7})
8
9app.use(
10 '/graphql',
11 graphqlHTTP({
12 schema: executableSchema,
13 context: data,
14 graphiql: true,
15 })
16)
17
18...
使用graphqlHTTP
中间软件需要通过方案和一个背景,在这种情况下,这是你的模仿数据存储。
您现在拥有开始服务端点所需的一切,您的server.js
代码应该是这样的:
1[label server.js]
2import express from 'express'
3import cors from 'cors'
4import { graphqlHTTP } from 'express-graphql'
5import { makeExecutableSchema } from '@graphql-tools/schema'
6
7const app = express()
8const port = 4000
9
10// In-memory data store
11const data = {
12 warriors: [
13 { id: '001', name: 'Jaime' },
14 { id: '002', name: 'Jorah' },
15 ],
16}
17
18// Schema
19const typeDefs = `
20type Warrior {
21 id: ID!
22 name: String!
23}
24
25type Query {
26 warriors: [Warrior]
27}
28`
29
30// Resolver for warriors
31const resolvers = {
32 Query: {
33 warriors: (obj, args, context) => context.warriors,
34 },
35}
36
37const executableSchema = makeExecutableSchema({
38 typeDefs,
39 resolvers,
40})
41
42app.use(cors())
43app.use(express.json())
44app.use(express.urlencoded({ extended: true }))
45
46// Entrypoint
47app.use(
48 '/graphql',
49 graphqlHTTP({
50 schema: executableSchema,
51 context: data,
52 graphiql: true,
53 })
54)
55
56app.listen(port, () => {
57 console.log(`Running a server at http://localhost:${port}`)
58})
保存并关闭文件,当你完成。
现在,您应该能够进入http://localhost:4000/graphql,并使用 GraphiQL IDE探索您的方案。
您的 GraphQL API 现在基于您在本节中创建的方案和解析器完成,在下一节中,您将使用 GraphiQL IDE 来帮助您解析和理解方案。
使用 GraphiQL IDE
由于您将graphiql
选项作为true
应用到 GraphQL 中间软件中,您可以访问 GraphiQL 集成开发环境 (IDE)。
GraphiQL 是用于编写、验证和测试 GraphQL 查询的浏览器中的工具,现在您可以测试您的 GraphQL 服务器,以确保它返回正确的数据。
对战士
进行查询,请求id
和name
属性. 在您的浏览器中,将以下行添加到 GraphiQL 的左面窗格:
1{
2 warriors {
3 id
4 name
5 }
6}
请按一下左上角的 **Play 箭头,然后在右边看到 JSON 中的返回值:
1[secondary_label Output]
2{
3 "data": {
4 "warriors": [
5 { "id": "001", "name": "Jaime" },
6 { "id": "002", "name": "Jorah" }
7 ]
8 }
9}
如果您删除查询中的一个字段,则会看到返回值相应的变化,例如,如果您只想要查找名称
字段,则可以这样写查询:
1{
2 warriors {
3 name
4 }
5}
现在你的答案将是这样的:
1[secondary_label Output]
2{
3 "data": {
4 "warriors": [{ "name": "Jaime" }, { "name": "Jorah" }]
5 }
6}
仅查询所需的字段的能力是 GraphQL 的强大方面之一,这使其成为一个 客户端驱动的语言。
在 GraphiQL 中,如果您点击 Docs 向右,它将扩展标记为 Documentation Explorer 的侧面栏。
现在您的 API 已经完成,您已经探索了如何从 GraphiQL 使用它,下一步将是从客户端向您的 GraphQL API 提出实际请求。
从客户端查询 GraphQL API
与 REST API一样,客户端可以通过在网络上进行 HTTP 请求来与 GraphQL API 进行通信. 由于您可以使用内置的浏览器 API 如fetch
来创建网络请求,您也可以使用fetch
来查询 GraphQL。
对于一个非常基本的例子,在一个index.html
文件中创建一个 HTML 骨骼,并使用一个<pre>
标签:
1[label index.html]
2<!DOCTYPE html>
3<html lang="en">
4 <head>
5 <meta charset="utf-8" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
8 <title>GraphQL Client</title>
9 </head>
10
11 <pre><!-- data will be displayed here --></pre>
12
13 <body>
14 <script>
15 // Add query here
16 </script>
17 </body>
18</html>
在脚本
标签中,创建一个非同步函数,向 GraphQL API 发送一个POST
请求:
1[label index.html]
2...
3<body>
4 <script>
5 async function queryGraphQLServer() {
6 const response = await fetch('http://localhost:4000/graphql', {
7 method: 'POST',
8 headers: {
9 'Content-Type': 'application/json',
10 },
11 body: JSON.stringify({
12 query: '{ warriors { name } }',
13 }),
14 })
15 const data = await response.json()
16
17 // Append data to the pre tag
18 const pre = document.querySelector('pre')
19 pre.textContent = JSON.stringify(data, null, 2) // Pretty-print the JSON
20 }
21
22 queryGraphQLServer()
23 </script>
24 </body>
25...
内容类型
标题必须设置为应用程序/json
,并将查询作为字符串传输到体内,脚本将调用函数来提出请求,并将答案设置为预先
标签。
这里是完整的index.html
代码。
1[label index.html]
2<!DOCTYPE html>
3<html lang="en">
4 <head>
5 <meta charset="utf-8" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
8 <title>GraphQL</title>
9 </head>
10
11 <pre></pre>
12
13 <body>
14 <script>
15 async function queryGraphQLServer() {
16 const response = await fetch('http://localhost:4000/graphql', {
17 method: 'POST',
18 headers: {
19 'Content-Type': 'application/json',
20 },
21 body: JSON.stringify({
22 query: '{ warriors { name } }',
23 }),
24 })
25 const data = await response.json()
26
27 const pre = document.querySelector('pre')
28 pre.textContent = JSON.stringify(data, null, 2) // Pretty-print the JSON
29 }
30
31 queryGraphQLServer()
32 </script>
33 </body>
34</html>
保存并关闭文件,当你完成。
现在,当您在浏览器中查看 index.html
文件时,您将看到向 http://localhost:4000/graphql
终端发出的网络请求,该终端将与数据一起返回 200
。
如果您的请求顺利完成,并且您收到来自 GraphQL API 的数据的200
响应,恭喜您!您创建了您的第一个 GraphQL API 服务器。
结论
在本教程中,您使用了 Node.js 中的 Express 框架创建了一个 GraphQL API 服务器. 该 GraphQL 服务器由一个单一的 `/graphql' 终端组成,可以处理传入请求来查询数据存储。
希望这篇文章有助于解密GraphQL,并开辟了与GraphQL可以实现什么的新想法和可能性. 有许多工具可以帮助您处理与GraphQL合作的更复杂方面,如身份验证,安全和缓存,但学习如何以最简单的方式设置API服务器应该帮助您了解GraphQL的基本知识。
本教程是我们如何使用 GraphQL 管理数据(https://www.digitalocean.com/community/tutorial_series/how-to-manage-data-with-graphql)系列的一部分,它涵盖了使用 GraphQL 的基本知识。