我尝试将GraphQL放置在Next.js的API路由中并运行了起来
从Gatsby.js(Next.js)的主题开发中学习【React.js × GraphQL】的博客系统获取文章信息。
Next.js的API路由是什么?
参考文献
API的根目录(官方文档)
在/pages/api/目录下放置的文件将被映射到/api/*,作为API的端点进行处理。例如,下面的API路径/pages/api/user.js将返回简单的JSON数据。
export default (req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ name: 'Jhon Doe' }))
}
要想使API路由功能生效,需要使用”export default”关键字来导出函数(处理程序)。req是http.IncomingMessage的实例,res是http.ServerResponse的实例。
使用GraphQL的API路径
我搜索了很多有关在Next.js中实现GraphQL的方法,但却发现眼前的事物比较难以理解,公式文档提供了简洁的源代码。

参考文献:使用GraphQL服务器的API路由 – GitHub
文件结构
-
- package.json
-
- pages/
index.js
api/
graphql.js
请看一下示例代码。
{
"name": "api-routes-graphql",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"apollo-server-micro": "2.6.7",
"graphql": "14.4.2",
"isomorphic-unfetch": "3.0.0",
"next": "latest",
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
"license": "ISC"
}
import { ApolloServer, gql } from 'apollo-server-micro'
const typeDefs = gql` // スキーマ定義
type Query { // クエリ定義
users: [User!]!
}
type User { // データ型定義
name: String
}
`
const resolvers = { // データ取得処理
Query: {
users(parent, args, context) {
return [
{ name: 'データ1' },
{ name: 'データ2' }
]
},
},
}
const apolloServer = new ApolloServer({ typeDefs, resolvers }) // GraphQL設定のインスタンス生成
export const config = { // ここはなんだ?
api: {
bodyParser: false,
},
}
export default apolloServer.createHandler({ path: '/api/graphql' }) // エンドポイントの指定
import fetch from 'isomorphic-unfetch'
const Index = ({ users }) => ( // コンポーネント内でJSONデータを使用するので引数に渡している
<div>
{users.map((user, i) => ( // 受け取ったJSONデータi個分を網羅して処理する
<div key={i}>{user.name}</div>
))}
</div>
)
Index.getInitialProps = async () => { // ここはなんだ?
const response = await fetch('http://localhost:3000/api/graphql', {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ query: '{ users { name } }' }),
})
const { data: { users }} = await response.json() // 取得したJSONデータをdataオブジェクトで受け取る
return { users } // 取得したJSONを返す
}
export default Index
管理已安装的软件包
查看package.json文件后发现,除了Next.js的标准安装项目之外,还安装了apollo-server-micro、praphql和isomorphic-unfetch这些模块。
apollo-server-micro使用Micro来处理通过/graphql端点的GraphQL请求。
GraphQL是JavaScript的参考实现。
isomorphic-unfetch 是一个能在客户端和服务器端进行无损获取和节点获取切换的工具。这可能是为了获取JSON文件之类的东西吗?
参考文献
apollo-server-micro – npm
graphql – npm
isomorphic-unfetch – npm以上是参考文献
apollo-server-micro – npm
graphql – npm
isomorphic-unfetch – npm的一些选项
当您自行安装这些时,请按照以下步骤。
$ npm i --save graphql apollo-server-micro isomorphic-unfetch
关于模式的设置
通过导入Apollo,我们可以在学习过程中理解到一些通过gql“”可以定义模式的方法。我认为它是一个可以使用普通GraphQL的模块,但在此之前,我们不知道该如何实施它。然而,在本文中,我们发现了Next.js的API路由这一具体的实施方式,可以使GraphQL运行起来。
由于已经学习了GraphQL编码的基础知识,因此在graphql.js代码中我没有遇到特别困难的地方。typeDefs是用于定义模式的,而resolvers则用于处理数据获取操作。
相关文章
【GraphQL 入门】学习笔记:在Next.js制作的博客中实现获取文章信息的API
由于我还不理解这里的typeDefs用法,所以先大致查一下代码才能读懂。首先,[User!]!的写法表示users是预留的用来存放数据的数组,User是自定义的数据类型名称,User!表示数组中的值不能为空,[ ]!表示数组不能为空,换句话说,查询时应该是“在users中非空的数组中的非空值”。如果从数据源返回null,则会报错。关于模式的理解,需要阅读官方文档中的“模式和类型”部分。
列举数据类型定义中的典型例子。
Int 整数型
Float 浮動小数点型
String UTF-8文字列型
Boolean ブーリアン型
ID 一意の識別子を表し、オブジェクトの再取得やキャッシュのキーとして使用
尝试意译一下代码中“スキーマ部分”的含义。
const typeDefs = gql`
type Query {
users: [User!]!
}
type User {
name: String
}
`
在GraphQL中,有一个名为Query的对象定义,通过名为users的查询,获取一个名为User的数组。User对象的定义是具有一个名为name的String类型字段。至于这个Query对象是从哪里来的,可以说它是从下面的代码中默认地在GraphQL中定义的。
顺便提一下,GraphQL的Query可以被视为相当于REST中的GET请求。
schema {
query: Query
mutation: Mutation
}
文献引用
Schemas和Types #Lists和Non-Null – 官方文件
学习GraphQL的Web API初学者
GraphQL服务器的解析函数
GraphQL服务器可以使用各种语言构建。Resolver函数可以传递四个参数。
obj 処理を決定するためのスキーム情報が入っていると思われる。ルートQueryタイプのフィールドでは、多くの場合、使用されない前のオブジェクト。
args GraphQLクエリのフィールドに渡される引数。
context 全てのリゾルバに渡され、現在ログイン中のユーザやDBへのアクセスなどの重要なコンテキスト情報を保持する値。
info 現在のクエリとスキーマの詳細に関連するフィールド固有の情報を保持する値。詳細はGraphQLResolveInfo型を参照。
参考文献
<根字段与解决器 – 官方文档>
在官方文件中提到了上述的四个参数,但是样例代码中的parent是什么?经过调查发现,不同于schema信息的ogj,parent参数似乎是用来存放上一次的结果的。
parent 前のリゾルバー呼び出しの結果(詳細)。
args リゾルバーのフィールドの引数。
context 各リゾルバが読み書きできるカスタムオブジェクト。
info クエリASTおよびその他の実行情報が含まれています
如何从API的解析器函数中访问字段参数?
在以下示例中,将三个参数传递给名为”users”的查询,现阶段,将其写成模板即可。相信通过使用GraphQL进行开发并逐渐学习具体示例,最终能够理解。然后,在return语句中返回所需的对象数据。原本应该从数据库或JSON中获取数据,但首要任务是先在Next.js中运行GraphQL。这里准备的对象数据内容应符合定义为类型为User的数据类型。
const resolvers = {
Query: {
users(parent, args, context) {
return [
{ name: 'データ1' },
{ name: 'データ2' }
]
},
},
}
关于new ApolloServer()
下面这部分是创建ApolloServer的实例。先使用require引入ApolloServer,然后将typeDefs和resolvers作为参数传递给ApolloServer并使用new生成一个实例,最后将该实例赋值给apolloServer变量。
const apolloServer = new ApolloServer({ typeDefs, resolvers })
根据Apollo Server的官方文档,可以使用任何数据源来构建一个用于生产环境的自描述GraphQL API。它是一个开源的服务器,可以作为一个独立的服务器,成为现有的Node.js HTTP服务器的附加组件,或者运行在无服务器环境下。
我不太清楚。
如果使用apollo-server包,调用实例化的ApolloServer上的listen函数,可以通过将指定的选项传递给Node.js http.Server来启动服务器。
我不太明白。
只要给GraphQL服务器连接模块装备参数,这样可以吗?
参考文献
Apollo Server – 官方文件
apollo-server – GitHub
虽然如此,Apollo Server官方文档对于传入resolver的四个参数也有深入的解释,所以作为学习resolver的材料,可能应该先阅读这部分内容。此外,obj和parent的区别似乎是GraphQL表达式和Apollo Server表达式的差异。
应用程序配置
export const config = {
api: {
bodyParser: false,
},
}
据我所知,config与开发环境的配置有关,但我并不清楚将body-parser设为非活动状态要达到什么目的。暂且先将它放在脑海中,我不想在api中使用body-parser。
在使用Node.js开发和部署中,切换配置环境的参考文献。
前面我对于bodyParser的意义并不太了解,但看起来它是一个用来读取HTTP请求中与请求体相关的数据,并将解析结果传递给 req.body 的中间件。换句话说,我认为它可以用来获取通过GraphQL读取的JSON文件等数据并存放在 req.body 中。
参考文献
body-parser – Node.js入门
阿波罗萨巴克利恩多拉 (ā bō luó sā bā kè lì ēn duō lā)
在谷歌上找不到让人满意的答案。暂且不理解。可能是在路径上设置了GraphQL的端点。
export default apolloServer.createHandler({ path: '/api/graphql' })
要不要看公式文档
我查了很多资料,但最终我认为最可靠的还是阅读以下官方文件。GraphQL官方文件和Apollo Server官方文件。这些文件几乎都包含了架构和解析器等相似的内容,但视角略有不同,可以拓宽视野。
应该阅读的文件
Apollo Server – 官方文档
apollo-server – GitHub
将users查询传递给React组件。
用户: [用户!]! 是一个数组,所以可以使用map函数来遍历其中的内容,并将数据存入名为”user”的参数中。”i”是指id或者其它信息来源,是一个顺序号吗?无论如何,我现在得到了一个组件,其中包含了我想要的数据的名称。
const Index = ({ users }) => (
<div>
{users.map((user, i) => (
<div key={i}>{user.name}</div>
))}
</div>
)
(中略)
export default Index
正在做某事的部分
将users作为参数传递给React组件,并使用map方法对用户数量进行迭代,逐个写出JSON的内容。
Index.getInitialProps = async () => {
const response = await fetch('http://localhost:3000/api/graphql', {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ query: '{ users { name } }' }),
})
const { data: { users }} = await response.json()
return { users }
}
打开应用程序
$ npm run dev
当连接到http://localhost:3000/时,会显示”数据1 数据2″。

那么,如何在Next.js中使用GraphQL的方法呢?
-
- 安装 apollo-server-micro graphql isomorphic-unfetch
-
- 在 API 根目录中设置 graphql.js 并定义模式等。
- 在 React 组件文件中将获取的 JSON 数据输出到 JSX 中。