我尝试将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的方法,但却发现眼前的事物比较难以理解,公式文档提供了简洁的源代码。

adf.png

参考文献:使用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″。

dfasdf.png

那么,如何在Next.js中使用GraphQL的方法呢?

    1. 安装 apollo-server-micro graphql isomorphic-unfetch

 

    1. 在 API 根目录中设置 graphql.js 并定义模式等。

 

    在 React 组件文件中将获取的 JSON 数据输出到 JSX 中。
bannerAds