教MERN堆栈说GraphQL
Apollo Server 是为与MERN堆栈(MongoDB、Express、React、Node)应用程序无缝工作而设计的。本教程展示了如何将Apollo Server添加到现有的MERN堆栈项目中。具体来说,本教程演示了如何:
- 运行一个 Apollo Server 实例,让您执行GraphQL 操作s
- 在MERN堆栈应用程序中公开一个 GraphQL 路线
先决条件
本教程假设您熟悉命令行和JavaScript。此外,还需要以下条件
- 您已安装最新的Node.js版本(
v14.16.0+
) - 您已完成MongoDB的MERN堆栈教程,或者您有现有的MERN堆栈应用程序。
- 本教程的代码示例基于教程,但您可以根据应用程序的要求对其进行修改。
- 您有一个具有
records
集合的MongoDB数据库,该集合具有name
,position
和level
列。- 本教程的代码示例使用这些列名,但您可以根据数据库的模式进行修改。
步骤 1:安装依赖项
在您的服务器文件夹中,运行以下命令以安装这些包并将它们保存到您的服务器项目的node_modules
目录中:
npm install graphql graphql-tag @apollo/subgraph @apollo/server
graphql
是GraphQL的JavaScript参考实现graphql-tag
是一个工具包,可将GraphQL字符串解析为标准的GraphQL抽象语法树(AST)@apollo/subgraph
是一个工具包,可创建GraphQL微服务@apollo/server
是一个符合规范的GraphQL服务器,它公开了/graphql
端点
步骤 2:定义您的GraphQL模式
每一个GraphQL服务器(包括Apollo Server)都使用一个模式来定义客户端可以查询的数据。以下示例为前置教程'的记录
集
在您的服务器的/src
文件夹中,创建一个schema.graphql
文件,并粘贴以下模式:
type Query {record(id:ID!): Recordrecords: [Record]}type Mutation {createRecord(name: String!, position: String, level: String): RecorddeleteRecord(id: ID!): BooleanupdateRecord(id: ID! name: String, position: String, level: String): Record}type Record {id: IDname: Stringposition: Stringlevel: String}
此模式允许您对记录执行各种操作:获取单个或多个记录、创建新记录、删除记录以及更新现有记录。有关模式定义的更多信息,请参阅模式基础文档。
步骤 3:定义解析器
解析器函数负责执行在模式中定义的操作——例如,获取和更新记录。在一个MERN堆栈应用程序中,它们是将GraphQL模式与您的MongoDB实例连接的方式。
在您的服务器的/src
文件夹中,创建一个新的resolvers.js
文件,并粘贴以下解析器:
import db from "./db/connection.js";const resolvers = {Record: {id: (parent) => parent.id ?? parent._id,},Query: {async record(_, { id }) {let collection = await db.collection("records");let query = { _id: new ObjectId(id) };return await collection.findOne(query);},async records(_, __, context) {let collection = await db.collection("records");const records = await collection.find({}).toArray();return records;},},Mutation: {async createRecord(_, { name, position, level }, context) {let collection = await db.collection("records");const insert = await collection.insertOne({ name, position, level });if (insert.acknowledged)return { name, position, level, id: insert.insertedId };return null;},async updateRecord(_, args, context) {const id = new ObjectId(args.id);let query = { _id: new ObjectId(id) };let collection = await db.collection("records");const update = await collection.updateOne(query,{ $set: { ...args } });if (update.acknowledged)return await collection.findOne(query);return null;},async deleteRecord(_, { id }, context) {let collection = await db.collection("records");const dbDelete = await collection.deleteOne({ _id: new ObjectId(id) });return dbDelete.acknowledged && dbDelete.deletedCount == 1 ? true : false;},},};export default resolvers;
你可能已经注意到了每个解析器的代码,与你的应用程序中/record
路由处的代码相似。这是因为这些解析器提供了与在记录集合上执行CRUD操作相同的逻辑。
要了解更多关于编写解析器函数的信息,请参阅解析器文档。
第4步:将Apollo Server添加到你的Express服务器
现在可以将Apollo Server集成到你的Express服务器中。无论你在哪里实例化你的express
服务器(通常为mern/server/server.js
),请导入@apollo/server
及其expressMiddleware
。然后,实例化和启动Apollo Server:
import express from 'express';import cors from 'cors';import records from "./routes/record.js";import gql from "graphql-tag";import { ApolloServer } from '@apollo/server';import { buildSubgraphSchema } from '@apollo/subgraph';import { expressMiddleware } from '@apollo/server/express4';import resolvers from "./resolvers.js";import { readFileSync } from "fs";const PORT = process.env.PORT || 5050;const app = express();app.use(cors());app.use(express.json());const typeDefs = gql(readFileSync("schema.graphql", {encoding: "utf-8",}));const server = new ApolloServer({schema: buildSubgraphSchema({ typeDefs, resolvers }),});// Note you must call `start()` on the `ApolloServer`// instance before passing the instance to `expressMiddleware`await server.start();app.use("/record", records);// start the Express serverapp.listen(PORT, () => {console.log(`Server is running on port: ${PORT}`);});
接下来,您将使用中间件将之前定义的解析器集成到一个路由中。
第5步:将/graphql
路由添加到您的服务器API端点
在同一个服务器文件中,添加/graphql
路由:
app.use("/record", records);// Specify the path to mount the serverapp.use('/graphql',cors(),express.json(),expressMiddleware(server),);app.listen(PORT, () => {console.log(`Server is running on port: ${PORT}`);});
此路由提供了访问Apollo Server的预先生成的解析器函数。注意,/records
路由尚未删除。这意味着你的Express服务器可以处理GraphQL和RESTful路由。
第6步:启动服务器
你现在可以启动服务器!从你的项目服务器目录中运行以下命令
npm start
你的控制台应该显示Server is running on port: 5050
。
第7步:执行你的第一个查询
你现在已经可以在服务器上执行GraphQL查询。要执行你的第一个查询,你可以使用Apollo Sandbox。
在你的浏览器中访问你的MERN服务器,在/graphql
路由,它将打开Apollo Sandbox:
沙箱UI包括
- 一个URL输入栏,用于连接到其他GraphQL服务器(在上左角)
- 用于模式探索、搜索和设置的选项卡(在左侧)
- 一个用于编写和执行查询的 操作面板(位于中间)
- 一个用于查看 查询结果的 响应面板(位于右侧)
要了解更多关于Sandbox提供的信息,请查看 Sandbox文档。
服务器支持 查询记录,让我们开始吧!将此GraphQL 查询字符串粘贴到 操作面板中并点击运行按钮以执行 records
查询。
query GetRecords {records {namepositionlevel}}
你应该在 响应面板中看到你的记录。
完整示例
你可以在Code Sandbox上查看和复制完整的服务器示例。
下一步
恭喜你完成了教程! 🎉 在你的MERN应用程序中集成GraphQL服务器是朝着创建更高效、灵活和以用户为中心的Web体验迈出的重要一步。现在,你已经将Apollo Server集成到你的MERN堆栈应用程序中,你就可以使用 GraphOS 来构建和更快地扩展了。
虽然这个教程只涵盖了MERN堆栈的服务器部分,但 /client
中的 完整示例继续了教程的剩余内容,并实现了 @apollo/client
与服务器交互。有关实现Apollo Client的更多信息,请参阅 入门文档。
为了更多地接触GraphQL和Apollo的服务器和客户端库,请查看我们的交互式 Odyssey教程。