共计 8804 个字符,预计需要花费 23 分钟才能阅读完成。
写在最后面
大家好呀,我是毛小悠,是一位前端开发工程师。正在翻译一本英文技术书籍。
为了进步大家的浏览体验,对语句的构造和内容略有调整。如果发现本文中有存在瑕疵的中央,或者你有任何意见或者倡议,能够在评论区留言,或者加我的微信:code
_maomao
,欢送互相沟通交流学习。
(σ゚∀゚)σ..:
*☆哎哟不错哦
第 4 章 咱们的第一个 GraphQL API
依据揣测,如果你正在浏览本文,那么你就是一个人。作为人类,你有很多趣味和喜好,你也有家人、敌人、熟人、同学和共事。这些人也有本人的社会关系、趣味和喜好。这些关系和趣味中有些重叠,有些没有。总而言之,咱们每个人都有咱们生存中人的关系图。这些类型的互连数据正是 GraphQL
最后提出要在 API
开发中解决的挑战。
通过编写 GraphQL API
,咱们可能高效地连贯数据,从而升高了复杂性和申请数量,同时使咱们可能精确地为客户提供所需的数据。听起来对Notes
应用程序来说有点过了,是吗?兴许是吧,然而正如你将看到的,GraphQL JavaScript
生态系统提供的工具和技术都能够启用和简化所有类型的 API
开发。
在本章中,咱们将应用 apollo-server-express
包来构建 GraphQL API
。为此,咱们将探索GraphQL
的根本主题,编写 GraphQL
模式,编写代码以解析模式性能,并应用 GraphQL Playground
用户界面拜访API
。
将咱们的服务器转换为 API(排序)
让咱们通过应用以下命令将 Express
服务器变成 GraphQL
服务器来开始 API
开发。
apollo-server-express
软件包。
Apollo Server
是一个开源 GraphQL
服务器库,可与大量 Node.js
服务器框架一起应用,包含 Express
,Connect
,Hapi
和Koa
。
GraphQL API
,可从 Node.js
应用程序中获取数据,还提供了有用的工具,例如GraphQL Playground
,一个可视化的辅助器,帮忙咱们在开发中查看API
。
要编写咱们的 API
,咱们将批改上一章中编写的Web
应用程序的代码。让咱们首先开始于 apollo-server-express
软件包。
将以下内容增加到 src/index.js
文件的顶部:
const {ApolloServer, gql} = require('apollo-server-express');
当初咱们曾经导入了 apollo
服务器,咱们将建设一个根本的 GraphQL
应用程序。
GraphQL
应用程序由两个次要组件组成:类型定义和解析器,用于解析针对数据执行的查问和批改。
这听起来像是胡话,但没关系。
咱们将实现“ Hello World
” API
响应,并将在咱们 API
的整个开发过程中进一步探讨这些 GraphQL
主题。
首先,让咱们构建一个基本模式,将其存储在一个名为 typeDefs
的变量中。
该模式将形容一个名为 hello
的查问,该查问将返回一个字符串:
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {hello: String}
`;
当初咱们曾经设置了构造,咱们能够增加一个解析器,该解析器将向用户返回一个值。这只是一个简略的函数,返回字符串“ Hello world
!”:
// Provide resolver functions for our schema fields
const resolvers = {
Query: {hello: () => 'Hello world!'
}
};
最初,咱们将集成 Apollo Server
以提供GraphQL API
。
为此,咱们将增加一些特定于 Apollo Server
的设置和中间件,并更新咱们的应用程序。
监听代码:
// Apollo Server setup
const server = new ApolloServer({typeDefs, resolvers});
// Apply the Apollo GraphQL middleware and set the path to /api
server.applyMiddleware({app, path: '/api'});
app.listen({port}, () =>
console.log(`GraphQL Server running at http://localhost:${port}${server.graphqlPath}`
)
);
综上,咱们的 src/index.js
文件当初应如下所示:
const express = require('express');
const {ApolloServer, gql} = require('apollo-server-express');
// Run the server on a port specified in our .env file or port 4000
const port = process.env.PORT || 4000;
// Construct a schema, using GraphQL's schema language
const typeDefs = gql`
type Query {hello: String}
`;
// Provide resolver functions for our schema fields
const resolvers = {
Query: {hello: () => 'Hello world!'
}
};
const app = express();
// Apollo Server setup
const server = new ApolloServer({typeDefs, resolvers});
// Apply the Apollo GraphQL middleware and set the path to /api
server.applyMiddleware({app, path: '/api'});
app.listen({port}, () =>
console.log(`GraphQL Server running at http://localhost:${port}${server.graphqlPath}`
)
);
如果你没有运行 nodemon
过程,则能够间接进入浏览器。否则,你必须在终端应用程序中输出 npm
运行 dev
以启动服务器。而后拜访http://localhost:4000/api
,在这里你会看到GraphQL Playground
(图4-1
)。
该 Web
应用程序与 Apollo Server
捆绑在一起,是应用 GraphQL
的微小益处之一。从这里,你能够运行 GraphQL
查问和批改并查看后果。
你也能够单击“Schema
”选项卡来拜访为 API
主动创立的文档。
图4-1
。GraphQL Playground
留神
GraphQL Playground
具备深色的默认语法主题。在整本书中,我将应用“浅色”主题以进步对比度。
这能够在 GraphQL Playground
的设置中进行配置,能够通过单击齿轮图标进行拜访。当初,咱们能够针对咱们的 GraphQL API
编写查问。为此,在 GraphQL Playground
中键入以下内容:
query {hello}
当你单击“播放”按钮时,查问应返回以下内容(图4-2
):
{
"data": {"hello": "Hello world!"}
}
图4-2
。你好查问
就是这样!当初,咱们曾经能够通过 GraphQL Playground
拜访无效的 GraphQL API
。咱们的API
会查问hello
,并返回字符串Hello world
!。
更重要的是,咱们当初具备了性能构建齐全的 API
的构造。
????
GraphQL 根底
在上一节中,咱们深入探讨并开发了咱们的第一个 API
,先让咱们花一些工夫后退一步来看看GraphQL API
的不同局部。
GraphQL API
的两个次要构建模块是模式和解析器。
通过了解这两个组件,能够更无效地将它们利用于 API
设计和开发。
Schemas
模式是咱们的数据和交互的书面示意。
通过申请一个模式,GraphQL
标准了咱们的 API
申请。
这是因为你的 API
只能返回数据并执行架构中定义的交互。
GraphQL
模式的根本组成部分是对象类型。
在后面的示例中,咱们创立了一个 GraphQL
对象类型的 Query
,带有一个hello
字段,该对象返回了规范的 String
类型。
GraphQL
蕴含五种内置标量类型:
- 串
:String
具备
UTF-8
字符编码的字符串 - 布尔型
Boolean
正确或谬误的值
- 整数
Int
32
位整数 - 浮点型
Flaot
浮点值
ID
惟一标识符
应用这些根本组件,咱们能够为 API
构建一个模式。
咱们首先定义类型。假如咱们正在为披萨菜单创立一个API
。
这时,咱们能够定义披萨的 GraphQL
模式类型,如下所示:
type Pizza {}
当初,每个披萨饼都有惟一的ID
,大小(例如小,中或大),切片数和可选的浇头。
Pizza
模式可能看起来像这样:
type Pizza {
id: ID
size: String
slices: Int
toppings: [String]
}
在此架构中,某些字段值是必须的(例如ID
,大小和切片),而其余字段值则是可选的(例如配料)。咱们能够应用感叹号来示意字段必须蕴含一个值。
让咱们更新构造以示意所需的值:
type Pizza {
id: ID!
size: String!
slices: Int!
toppings: [String]
}
在本书中,咱们将编写一个基本模式,这将使咱们可能执行常见 API
中的绝大多数操作。如果你想摸索所有的 GraphQL
模式选项,倡议你浏览 GraphQL
模式文档。
解析器Resolvers
GraphQL API
的第二局部是解析器。
解析程序齐全执行其名称所暗示的操作;他们解析 API
而后获取用户已申请的数据。
咱们将首先在构造中定义这些解析器,而后在 JavaScript
代码中实现逻辑,以编写这些解析器。
咱们的 API
将蕴含两种类型的解析器:查问和批改。
查问
查问从 API
申请中获取所需格局的特定数据。
在咱们假如的披萨 API
中,咱们能够编写一个查问,该查问将返回菜单上披萨的残缺列表,而另一个查问将返回无关单个披萨的详细信息。而后查问将返回一个对象,其中蕴含 API
中用户申请的数据。查问从不批改数据,仅拜访数据。
批改
当咱们想要批改 API
中的数据时,咱们应用一个批改。
在咱们的披萨示例中,咱们可能编写了一个批改,该批改能够更改给定披萨的配料,而另一个批改则能够调整切片数。
与查问相似,也冀望批改以对象的模式返回后果,通常是所执行操作的最终后果。
调整咱们的 API
当初你曾经对 GraphQL
的组件有了很好的理解,让咱们为 Notes
应用程序调整咱们的初始 API
代码。
首先,咱们将编写一些代码来浏览和创立笔记。咱们须要做的第一件事是为 API
提供一些数据。让咱们创立一个“笔记”对象数组,将其用作 API
提供的根本数据。随着我的项目的倒退,咱们将用数据库替换这个数据。
当初,咱们将数据存储在一个名为 notes
的变量中。数组中的每个笔记将是一个具备三个属性(id
,content
和author
)的对象:
let notes = [{ id: '1', content: 'This is a note', author: 'Adam Scott'},
{id: '2', content: 'This is another note', author: 'Harlow Everly'},
{id: '3', content: 'Oh hey look, another note!', author: 'Riley Harrison'}
];
当初咱们有了一些数据,咱们将调整咱们的 GraphQL API
来应用它。
让咱们从关注咱们的模式开始。咱们的模式是 GraphQL
对咱们的数据以及如何与之交互的示意。已知咱们会有笔记,这些笔记将被查问和批改。这些笔记目前将蕴含 ID
、内容和作者3
个字段。
让咱们在 typeDefs GraphQL
模式中创立一个相应的笔记类型。
以下示意咱们 API
中笔记的属性:
type Note {
id: ID!
content: String!
author: String!
}
当初,让咱们增加一个查问,该查问将容许咱们检索所有笔记的列表。
让咱们更新一个笔记查问,这将返回笔记对象的数组:
type Query {
hello: String!
notes: [Note!]!
}
当初,咱们能够更新解析器代码以执行返回数据数组的工作。
让咱们更新包含以下笔记解析器的查问代码,该解析器返回原始数据对象:
Query: {hello: () => 'Hello world!',
notes: () => notes},
如果当初切换到运行在 http://localhost:4000/api
的GraphQL Playground
,咱们能够测试笔记查问。
为此,请键入以下查问:
query {
notes {
id
content
author
}
}
而后,当你单击“播放”按钮时,应该看到返回的数据对象,其中蕴含数据数组(图4-3
)。
图4-3
。笔记查问。
在尝试 GraphQL
最酷的方面之一是咱们能够删除任何申请的字段,例如 id
或author
。当咱们这样做时,API
准确地返回咱们所申请的数据。
这样,应用数据的客户端能够管制每个申请中发送的数据量,并将该数据限度在所需的范畴内(图4-4
)。
图4-4
。笔记查问,仅申请内容数据。
当初咱们能够查问残缺的笔记列表,让咱们编写一些代码,使咱们能够查问单个笔记。
从用户界面的角度,你能够设想这样做的用途,能够显示蕴含单个特定笔记的视图。为此,咱们心愿申请带有特定 id
值的笔记。这要求咱们应用 GraphQL
模式中的参数。参数容许 API
使用者将特定的值传递给解析器函数,从而提供解析所需的信息。让咱们增加一个笔记查问,该查问将应用 id
类型的 ID
作为参数。
咱们将 typeDefs
中的 Query
对象更新为以下内容,其中包含新的笔记查问:
type Query {
hello: String
notes: [Note!]!
note(id: ID!): Note!
}
更新构造后,咱们曾经能够编写在查问解析器后返回的笔记了。当初咱们须要可能读取 API
用户的参数值。
有用信息
Apollo Server
将以下有用的参数传递给咱们的解析器性能:
parent
父查问的后果,在嵌套查问时很有用。
args
这些是用户在查问中传递的参数。
context
信息从服务器应用程序传递到解析器性能。
这可能包含诸如以后用户或数据库信息之类的信息。
info
无关查问自身的信息。
咱们将依据须要在代码中进一步摸索这些内容。如果你感到好奇,能够在 Apollo
服务器的文档中理解无关这些参数的更多信息。
当初,咱们仅须要第二个参数 args
中蕴含的信息。
笔记查问将笔记 ID
作为参数,在咱们的笔记对象数组中找到它。将以下内容增加到查问解析器代码中:
note: (parent, args) => {return notes.find(note => note.id === args.id);
}
解析器代码当初应如下所示:
const resolvers = {
Query: {hello: () => 'Hello world!',
notes: () => notes,
note: (parent, args) => {return notes.find(note => note.id === args.id);
}
}
};
运行咱们的查问,让咱们返回到 Web
浏览器并拜访位于 http://localhost:4000/api
的GraphQL Playground
。
当初,咱们能够查问具备特定 ID
的笔记,如下所示:
query {note(id: "1") {
id
content
author
}
}
运行此查问时,你应该收到带有申请的 id
值的笔记的后果。如果你尝试查问不存在的笔记,则应收到后果为 null
的后果。要对此进行测试,请尝试更改 id
值以返回不同的后果。
让咱们通过应用 GraphQL
批改引入创立新笔记的性能来强化咱们的初始 API
代码。在这种批改中,用户将传递笔记的内容。
当初,咱们将对笔记的作者进行编码。
让咱们首先应用 Mutation
类型更新咱们的 typeDefs
模式,咱们将其称为newNote
:
type Mutation {newNote(content: String!): Note!
}
当初,咱们将编写一个批改解析器,它将笔记内容作为参数,将笔记存储为对象,而后将其增加到 notes
数组中。咱们将 Mutation
对象增加到解析器。
在 Mutation
对象中,咱们将增加一个名为 newNote
的函数,该函数具备 parent
和args
参数。在此函数中,咱们将应用参数 content
并创立一个具备 id
,content
和author
键的对象。
你可能曾经留神到,这与笔记的以后模式匹配。而后,咱们将该对象退出到 notes
数组并返回该对象。返回的对象容许 GraphQL
批改接管预期格局的响应。
持续并编写以下代码:
Mutation: {newNote: (parent, args) => {
let noteValue = {id: String(notes.length + 1),
content: args.content,
author: 'Adam Scott'
};
notes.push(noteValue);
return noteValue;
}
}
咱们的 src/index.js
文件当初将如下所示:
const express = require('express');
const {ApolloServer, gql} = require('apollo-server-express');
// Run our server on a port specified in our .env file or port 4000
const port = process.env.PORT || 4000;
let notes = [{ id: '1', content: 'This is a note', author: 'Adam Scott'},
{id: '2', content: 'This is another note', author: 'Harlow Everly'},
{id: '3', content: 'Oh hey look, another note!', author: 'Riley Harrison'}
];
// Construct a schema, using GraphQL's schema language
const typeDefs = gql`
type Note {
id: ID!
content: String!
author: String!
}
type Query {
hello: String
notes: [Note!]!
note(id: ID!): Note!
}
type Mutation {newNote(content: String!): Note!
}
`;
// Provide resolver functions for our schema fields
const resolvers = {
Query: {hello: () => 'Hello world!',
notes: () => notes,
note: (parent, args) => {return notes.find(note => note.id === args.id);
}
},
Mutation: {newNote: (parent, args) => {
let noteValue = {id: String(notes.length + 1),
content: args.content,
author: 'Adam Scott'
};
notes.push(noteValue);
return noteValue;
}
}
};
const app = express();
// Apollo Server setup
const server = new ApolloServer({typeDefs, resolvers});
// Apply the Apollo GraphQL middleware and set the path to /api
server.applyMiddleware({app, path: '/api'});
app.listen({port}, () =>
console.log(`GraphQL Server running at http://localhost:${port}${server.graphqlPath}`
)
);
更新构造和解析器以承受批改后,让咱们在 GraphQL Playground
的http://localhost:4000/api
上进行尝试。
在 Playground
上,单击 + 号以创立一个新选项卡,并按如下所示编写变量:
mutation {newNote (content: "This is a mutant note!") {
content
id
author
}
}
当你单击“播放”按钮时,你应该会收到蕴含新笔记的内容、ID
和作者的后果。
你还能够通过从新运行 notes
查问来查看该批改是否起作用。
为此,请切换回蕴含该查问的 GraphQL Playground
选项卡,或键入以下内容:
query {
notes {
content
id
author
}
}
运行此查问时,你当初应该看到四个笔记,包含最近增加的笔记。
数据存储
咱们将数据存储在内存中。这意味着,只有咱们重新启动服务器,就会失落该数据。在下一章中,咱们将应用数据库来长久化数据。
当初,咱们曾经胜利实现了查问和批改解析器,并在 GraphQL Playground
用户界面中对其进行了测试。
论断
在本章中,咱们曾经应用 apollo-server-express
模块胜利构建了 GraphQL API
。当初,咱们能够对内存中的数据对象运行查问和批改。此设置为咱们提供了构建任何API
的坚实基础。在下一章中,咱们将探讨应用数据库长久化数据的能力。
如果有了解不到位的中央,欢送大家纠错。如果感觉还能够,麻烦您点赞珍藏或者分享一下,心愿能够帮到更多人。