Building a GraphQL Server with Node.js and Express Building a GraphQL Server with Node.js and Express

2025-06-04

使用 Node.js 和 Express 构建 GraphQL 服务器

使用 Node.js 和 Express 构建 GraphQL 服务器


使用 Node.js 和 Express 构建 GraphQL 服务器

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

本文是 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
Enter fullscreen mode Exit fullscreen mode

接下来让我们创建一个expressHTTP 服务器,如下所示:

// 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;
Enter fullscreen mode Exit fullscreen mode

这是一个非常简单的模式,它将helloperson和声明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!`));
Enter fullscreen mode Exit fullscreen mode

上面我们通过调用以下方法声明了默认路由:

app.get("/", (req, res) => {
});
Enter fullscreen mode Exit fullscreen mode

然后我们graphql通过使用参数schema和调用它来添加该部分query,如下所示:

graphql(schema, query).then(result => {
  res.json(result);
});
Enter fullscreen mode Exit fullscreen mode

正如我们上面所见,调用graphql意味着我们得到了一个 Promise,并且在then()回调中我们可以看到查询的结果。总而言之,我们可以看到它们是如何graphql交互express的。

最后,为了运行它,我们需要在文件中指定一个start命令package.json来调用对 ESM 模块的实验性支持。它应该如下所示:

// excerpt from package.json
"start": "node — experimental-modules app.mjs"
Enter fullscreen mode Exit fullscreen mode

添加 express-graphql

我们刚刚展示了如何使用expressgraphql创建 REST API,但我们可以通过添加来做得更好express-graphql,所以让我们将其作为下一步:

npm install express-graphql
Enter fullscreen mode Exit fullscreen mode

让我们先为自己做点别的事情,即使用该buildSchema()方法并以此方式建立一个模式,如下所示:

var { buildSchema } = require("graphql");
var schema = buildSchema(`
  type Product {
    name: String,
    id: Int
  },
  type Query {
    hello: String,
    products: [Product]
  }
`);
Enter fullscreen mode Exit fullscreen mode

上面我们可以看到我们定义了自定义类型Product,并且我们还定义了我们的查询是helloproducts

我们还需要一些解析器函数,如下所示:

const getProducts = () => {
  return Promise.resolve([{
    title: 'Movie'
  }]);
}  

var root = {
  hello: () => {
    return "Hello world!";
  },
  products: () => {
    return getProducts();
  }
};
Enter fullscreen mode Exit fullscreen mode

最后,我们可以稍微清理一下代码,这样启动服务器的代码现在看起来就像这样:

var graphqlHTTP = require("express-graphql");
app.use(
  '/graphql',
  graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true
  })
);
Enter fullscreen mode Exit fullscreen mode

就是这样,我们实际上不需要定义任何路由,而是将其留给 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
}
Enter fullscreen mode Exit fullscreen mode

现在是时候编写我们的实际查询了,所以让我们接下来这样做:

product(id: $id) {
  name
}
Enter fullscreen mode Exit fullscreen mode

正如您所看到的,我们使用了$id查询构造,完整结果如下所示:

query Query($id: Int!) {
  product(id: $id) {
    name
  }
}
Enter fullscreen mode Exit fullscreen mode

注意:屏幕底部有一个名为的部分query variables,用于定义要用作输入的变量。因此,当我们定义某些内容时,$name_of_variable它会查找该query variables部分

调用 Mutation

要调用突变,我们需要mutation关键字。接下来让我们创建突变调用:

mutation MyMutation {
  addProduct(name: "product", description: "description of a product") 
}
Enter fullscreen mode Exit fullscreen mode

注意:如果我们返回一个复杂的对象,我们需要选择我们想要的列,像这样

mutation MyMutation {
  addProduct(name: "product", description: "description of a product"){ 
    col1, 
    col2 
  }
}
Enter fullscreen mode Exit fullscreen mode

概括

为了构建 API,我们使用了 NPM 库expressgraphql但是,通过添加,express-graphql我们获得了一个名为的可视化环境,graphiql它使我们能够提出查询并运行变更,以便我们可以验证 API 是否按预期工作

如果你想查看现有的 repo,请查看此处的Demo repo

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

文章来源:https://dev.to/azure/building-a-graphql-server-with-nodejs-andexpress-5hfh
PREV
像 Hipster 一样使用 GitHub Actions 在 Azure 上部署你的网站
NEXT
为每个想要进行技术演示的人提供的指南👇🏻为什么要演讲?