使用 Node.js 和 Express 构建 GraphQL 服务器
使用 Node.js 和 Express 构建 GraphQL 服务器
使用 Node.js 和 Express 构建 GraphQL 服务器
在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris
本文是 GraphQL 系列文章的一部分:
- 使用 Node.js 和 Express 构建 GraphQL 服务器,我们在这里
- 使用 Node.js 和 Apollo 框架构建 GraphQL 服务器
- 使用 React 使用 Apollo GraphQL 服务器
GraphQL 使我们能够构建一个客户端可以以任何方式查询的服务器。我当然指的是内容协商,即能够以任意深度向服务器精确请求所需的字段或资源。
在上一篇文章《构建你的第一个 GraphQL 服务器》中,我介绍了构成 GraphQL 服务器的不同构件和类型。在本文中,我们将重点介绍如何构建一个由 GraphQL 驱动、可供客户端使用的服务。我们还将介绍一个名为 GraphiQL 的测试环境,它提供了一个 UI,我们可以在其中测试查询。
在本文中,我们将介绍:
- 为什么选择 Graphql,Graphql 是一项很棒的新技术,让我们尝试解释一下它为什么重要,以及为什么它能让 API 的构建变得有趣和简单
- 构建块,让我们来看看构建 Graphql 服务器端所需的构建块
- 构建服务器,我们将使用 Node.js、Express 和一个名为 express-graphql 的库来实现
- 查询,我们将介绍查询服务器的不同方式,如普通查询、参数化查询以及如何通过突变更改数据
为什么使用 GraphQL
选择 GraphQL 而不是 REST 有很多原因:
- 您需要的数据。与所有使用内容协商的技术一样,您可以只查询所需的数据,这意味着您可以获得所需的列,并将返回结果保持在最低限度。尤其是在当今移动优先和 3G/4G 连接盛行的时代,将数据响应保持在最低限度是一件非常棒的事情。
- 一个端点,只要您需要从某个端点获取特定数据,就可以查询该特定端点。如果您需要的数据需要从多个端点拼凑在一起,该怎么办?这时,您需要执行一系列调用或构建一个新的端点。无论您选择哪种方法,都需要花时间管理和了解您的端点。GraphQL 在这方面表现出色,因为它只有一个端点。
- 序列化,当你调用 REST 时,你会得到 JSON 格式的响应。但是,你可能需要对数据进行一些额外的处理,例如重命名列,以更好地适应你的应用程序。使用 GraphQL,你可以在查询语句中指定这些操作。
- 深入研究,通常使用 REST 可以轻松处理像订单这样的具体事物。如果您想获取该订单中的订单项,甚至是客户购买的产品,该怎么办?很可能您需要进行多次调用或执行特定的报告查询,以避免额外的往返。使用 GraphQL,您可以在图中根据需要进行任意深度的查询,并以任意深度提取所需的数据。当然,以高效的方式执行此操作是 GraphQL 面临的更大挑战之一,它并非总是充满阳光和美好。GraphQL 并非万能的灵丹妙药,但它可以让生活变得轻松很多。
构建块
GraphQL 服务器由以下内容组成:
- 一个模式,该模式定义了我们的实体,也定义了我们可以查询或调用的突变
- 解析器,解析器函数与第三方 API 或我们的数据库对话,最终将数据返回给我们的用户
安装依赖项
让我们首先安装所需的依赖项。我们需要以下内容:
- express,创建我们的 Web 服务器
- graphql,用于安装 graphql,这是我们的核心库,使我们能够利用 graphql
- express-graphql,这个库使我们能够将 graphql 和 express 绑定在一起
Express + graphql(仅限)
让我们从安装开始graphql
,并express
了解它能给我们带来什么:
npm install express graphql
接下来让我们创建一个express
HTTP 服务器,如下所示:
// schema.mjs
import {
graphql,
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLList
} from "graphql";
let humanType = new GraphQLObjectType({
name: "Human",
fields: () => ({
id: { type: GraphQLString },
description: { type: GraphQLString },
name: { type: GraphQLString }
})
});
import people from "./data/people";
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: "RootQueryType",
fields: {
hello: {
type: GraphQLString,
resolve() {
return "world";
}
},
person: {
type: humanType,
resolve() {
return people[0];
}
},
people: {
type: new GraphQLList(humanType),
resolve() {
return people;
}
}
}
})
});
export { graphql };
export default schema;
这是一个非常简单的模式,它将hello
、person
和声明people
为可查询关键字,并且还创建humanType
为自定义类型。
关于文件结尾的 ,简单说一下 .mjs
。我们这里做的是利用对ESM/EcmaScript
模块的实验性支持。NodeJS 目前实现模块的方式迫使我们使用以 结尾的文件 .mjs
。
接下来是应用程序本身,它只是一个基本的快速应用程序,如下所示:
// app.mjs
import express from "express";
const app = express();
const port = 3000;
import schema, { graphql } from "./schema";
app.get("/", (req, res) => {
let query = `{ hello, person { name }, people { name, description } }`;
graphql(schema, query).then(result => {
res.json(result);
});
});
app.listen(port, () => console.log(`Example app listening on port port!`));
上面我们通过调用以下方法声明了默认路由:
app.get("/", (req, res) => {
});
然后我们graphql
通过使用参数schema
和调用它来添加该部分query
,如下所示:
graphql(schema, query).then(result => {
res.json(result);
});
正如我们上面所见,调用graphql
意味着我们得到了一个 Promise,并且在then()
回调中我们可以看到查询的结果。总而言之,我们可以看到它们是如何graphql
交互express
的。
最后,为了运行它,我们需要在文件中指定一个start
命令package.json
来调用对 ESM 模块的实验性支持。它应该如下所示:
// excerpt from package.json
"start": "node — experimental-modules app.mjs"
添加 express-graphql
我们刚刚展示了如何使用express
和graphql
创建 REST API,但我们可以通过添加来做得更好express-graphql
,所以让我们将其作为下一步:
npm install express-graphql
让我们先为自己做点别的事情,即使用该buildSchema()
方法并以此方式建立一个模式,如下所示:
var { buildSchema } = require("graphql");
var schema = buildSchema(`
type Product {
name: String,
id: Int
},
type Query {
hello: String,
products: [Product]
}
`);
上面我们可以看到我们定义了自定义类型Product
,并且我们还定义了我们的查询是hello
和products
。
我们还需要一些解析器函数,如下所示:
const getProducts = () => {
return Promise.resolve([{
title: 'Movie'
}]);
}
var root = {
hello: () => {
return "Hello world!";
},
products: () => {
return getProducts();
}
};
最后,我们可以稍微清理一下代码,这样启动服务器的代码现在看起来就像这样:
var graphqlHTTP = require("express-graphql");
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
})
);
就是这样,我们实际上不需要定义任何路由,而是将其留给 graphql 处理。我们可以看到,这graphqlHTTP()
是一个从express-graphql
现在我们已经准备好一切了。
Graphiql
当我们调用我们的graphqlHTTP()
函数时,我们为其提供了一个具有以下属性设置的配置对象:
- schema,我们的 GraphQL 模式
- rootValue,我们的解析器函数
- graphiql,一个布尔值,表示是否使用
graphiql
,我们想要这个,所以我们true
在这里传递
下一步是尝试graphiql
通过导航到以下位置进行操作http://localhost:4000/graphql
,瞧,这就是您应该看到的:
好的,太好了,一个可视化界面,现在怎么办?
好了,现在你可以开始创建 Graphql 查询了。要知道要查询什么,请查看你在 schema 中定义的内容。
我们希望能够在模式中设置它们hello
并进行查询。那么让我们这样做:products
好的,点击play
图标后你应该会看到上面的内容。正如你所见,这是一个非常有用的工具,可以用来调试查询,但它也可以用来调试修改。
参数化查询
我们尝试在 graphiql 中编写一个带有参数的查询:
上面我们可以看到如何使用关键字 来定义查询query
。之后,我们给它一个名称,Query
后跟一个括号。括号内是我们用$
字符 表示的输入参数。在本例中,我们将参数称为id
,这意味着它的全名是$id
。让我们看看我们得到了什么:
query Query($id: Int!) {
// our actual query
}
现在是时候编写我们的实际查询了,所以让我们接下来这样做:
product(id: $id) {
name
}
正如您所看到的,我们使用了$id
查询构造,完整结果如下所示:
query Query($id: Int!) {
product(id: $id) {
name
}
}
注意:屏幕底部有一个名为的部分
query variables
,用于定义要用作输入的变量。因此,当我们定义某些内容时,$name_of_variable
它会查找该query variables
部分
调用 Mutation
要调用突变,我们需要mutation
关键字。接下来让我们创建突变调用:
mutation MyMutation {
addProduct(name: "product", description: "description of a product")
}
注意:如果我们返回一个复杂的对象,我们需要选择我们想要的列,像这样
mutation MyMutation {
addProduct(name: "product", description: "description of a product"){
col1,
col2
}
}
概括
为了构建 API,我们使用了 NPM 库express
。graphql
但是,通过添加,express-graphql
我们获得了一个名为的可视化环境,graphiql
它使我们能够提出查询并运行变更,以便我们可以验证 API 是否按预期工作
如果你想查看现有的 repo,请查看此处的Demo repo
在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris
文章来源:https://dev.to/azure/building-a-graphql-server-with-nodejs-andexpress-5hfh