使用 Node 构建 GraphQL API

已发表: 2022-12-20

GraphQL 是 API 开发中的新流行语。 虽然 RESTful API 仍然是从应用程序公开数据的最流行方式,但它们具有 GraphQL 旨在解决的许多限制。

GraphQL 是 Facebook 创建的一种查询语言,于 2015 年转变为一个开源项目。它提供了一种直观灵活的语法来描述和访问 API 中的数据。

本指南将探讨如何构建 GraphQL Node.js 项目。 我们将使用 GraphQL 在 Node 的 Express.js Web 框架中构建 Todo 应用程序。

什么是 GraphQL?

来自官方文档:“GraphQL 是一种 API 查询语言,也是一种使用现有数据完成这些查询的运行时。 GraphQL 为您的 API 中的数据提供了完整且易于理解的描述,使客户能够准确地询问他们需要什么,仅此而已,随着时间的推移更容易发展 API,并启用强大的开发人员工具。”

GraphQL 是一个服务器端运行时,用于使用您为数据定义的类型系统执行查询。 此外,GraphQL 不依赖于任何特定的数据库或存储引擎。 相反,它由您现有的代码和数据存储支持。 您可以通过 GraphQL 与 RESTful API 指南详细比较这些技术。

要创建 GraphQL 服务,您首先要定义架构类型并使用这些类型创建字段。 接下来,您提供一个函数解析器,在客户端请求数据时在每个字段和类型上执行。

GraphQL 术语

GraphQL 类型系统用于描述可以查询哪些数据以及可以操作哪些数据。 它是 GraphQL 的核心。 让我们讨论在 GraphQ 中描述和操作数据的不同方式。

类型

GraphQL 对象类型是包含强类型字段的数据模型。 您的模型和 GraphQL 类型之间应该存在一对一的映射。 以下是 GraphQL 类型的示例:

 type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }

查询

GraphQL 查询定义了客户端可以在 GraphQL API 上运行的所有查询。 您应该定义一个RootQuery ,它将按照约定包含所有现有查询。

下面我们定义查询并将其映射到相应的 RESTful API:

 type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }

突变

如果 GraphQL 查询是GET请求,则突变是操作 GraphQL API 的POSTPUTPATCHDELETE请求。

我们将把所有的突变放在一个单一的RootMutation中来演示:

 type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }

您注意到对UserInputTodoInput等突变使用了-input类型。 始终定义用于创建和更新资源的输入类型始终是最佳实践。

您可以像下面这样定义输入类型:

 input UserInput { firstname: String! lastname: String email: String! username: String! }

解析器

解析器告诉 GraphQL 在请求每个查询或变更时要做什么。 它是一项基本功能,负责执行 CRUD(创建、读取、更新、删除)操作、访问内部 RESTful API 端点或调用微服务来满足客户端请求等艰苦工作。

您可以创建一个新的resolvers.js文件并添加以下代码:

 import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }

图式

GraphQL 模式是 GraphQL 向世界公开的内容。 因此,类型、查询和变更将包含在模式中以向世界公开。

下面是如何向世界公开类型、查询和突变:

 schema { query: RootQuery mutation: RootMutation }

在上面的脚本中,我们包含了我们之前创建的RootQueryRootMutation以向世界公开。

GraphQL 如何与 Nodejs 和 Expressjs 一起工作

GraphQL 为所有主要编程语言提供了一种实现,Node.js 也不例外。 在 GraphQL 官方网站上,有一个 JavaScript 支持部分,还有 GraphQL 的其他实现,可以简化 GraphQL 的编写和编码。

GraphQL Apollo 为 Node.js 和 Express.js 提供了一个实现,使 GraphQL 的入门变得容易。

在下一节中,您将学习如何使用 GraphQL Apollo 在 Nodes.js 和 Express.js 后端框架中创建和开发您的第一个 GraphQL 应用程序。

使用 Express.js 设置 GraphQL

使用 Express.js 构建 GraphQL API 服务器非常容易上手。 在本节中,我们将探讨如何构建 GraphQL 服务器。

使用 Express 初始化项目

首先,您需要安装并设置一个新的 Express.js 项目。

为您的项目创建一个文件夹并使用以下命令安装 Express.js:

 cd <project-name> && npm init -y npm install express

上面的命令创建一个新的package.json文件并将 Express.js 库安装到您的项目中。

接下来,我们将构建我们的项目,如下图所示。 它将包含针对项目特性的不同模块,例如用户、待办事项等。

graphql-todo 中的文件列表。
graphql-todo 的文件。

初始化 GraphQL

让我们从安装 GraphQL Express.js 依赖项开始。 运行以下命令进行安装:

 npm install apollo-server-express graphql @graphql-tools/schema --save

创建模式和类型

接下来,我们将在 modules 文件夹中创建一个index.js文件并添加以下代码片段:

 const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;

代码演练

让我们完成代码片段并将其分解:

步骤1

首先,我们导入了所需的库并创建了默认查询和突变类型。 query 和 mutation 目前只设置 GraphQL API 的版本。 然而,我们将扩展查询和变异以包括我们继续进行的其他模式。

显示用于导入 GraphQL 和其他扩展的“常量”代码的命令行界面。
导入 GraphQL 和扩展。
第2步:

然后我们为时间创建了一个新的标量类型,并为上面创建的查询和变异创建了我们的第一个解析器。 此外,我们还使用makeExecutableEchema函数生成了一个模式。

生成的模式包括我们导入的所有其他模式,并且在我们创建和导入它们时还将包括更多。

为停机和 WordPress 问题苦苦挣扎? Kinsta 是旨在节省您时间的托管解决方案! 查看我们的功能
命令行界面显示用于创建标量类型和第一个解析器的“const”代码。
为时间创建标量类型以及我们的第一个解析器。

上面的代码片段显示我们将不同的模式导入到 makeExecutableEchema 函数中。 这种方法有助于我们针对复杂性构建应用程序。 接下来,我们将创建导入的 Todo 和 User 模式。

创建待办事项架构

Todo 模式显示了应用程序用户可以执行的简单 CRUD 操作。 下面是实现 Todo CRUD 操作的模式。

 const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };

代码演练

让我们完成代码片段并将其分解:

步骤1:

首先,我们使用 GraphQL typeinputextend为 Todo 创建了一个模式。 extend关键字用于继承和添加新的查询和变异到我们上面创建的现有根查询和变异。

显示我们的 Todo 脚本架构的命令行界面,包括新输入。
为我们的 Todo 创建模式。
第2步:

接下来,我们创建了一个解析器,用于在调用特定查询或突变时检索正确的数据。

一个命令行界面,显示为我们的待办事项创建解析器的代码。
创建解析器。

有了解析器函数,我们可以为业务逻辑和数据库操作创建单独的方法,如create-todo.js示例所示。

在 <code>./mutations</code> 文件夹中创建一个create-user.js文件,并添加业务逻辑以在您的数据库中创建一个新的 Todo。

 const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };

上面的代码片段是使用 Sequelize ORM 在我们的数据库中创建新 Todo 的简化方法。 您可以了解有关 Sequelize 以及如何使用 Node.js 进行设置的更多信息。

您可以按照相同的步骤根据您的应用程序创建许多模式,或者您可以从 GitHub 克隆整个项目。

接下来,我们将使用 Express.js 设置服务器并使用 GraphQL 和 Node.js 运行新创建的 Todo 应用程序

设置和运行服务器

最后,我们将使用之前安装的apollo-server-express库设置我们的服务器并对其进行配置。

apollo-server-express是 Apollo Server for Express.js 的简单包装器,推荐使用它是因为它的开发适合 Express.js 开发。

使用我们上面讨论的示例,让我们配置 Express.js 服务器以与新安装的 apollo-server-express一起工作。

在根目录中创建一个server.js文件并粘贴以下代码:

 const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );

在上面的代码中,您已经成功地为 Todos 和 Users 创建了您的第一个 CRUD GraphQL 服务器。 您可以启动开发服务器并使用 http://localhost:3000/graphql 访问 playground。 如果一切顺利,您应该会看到以下屏幕:

显示简单查询响应的开发界面。
验证屏幕。

概括

GraphQL 是 Facebook 支持的现代技术,它简化了使用 RESTful 架构模式创建大规模 API 所涉及的繁琐工作。

本指南阐明了 GraphQL 并演示了如何使用 Express.js 开发您的第一个 GraphQL API。

让我们知道您使用 GraphQL 构建了什么。