如何在Ubuntu18.04上使用Node.js和MongoDB构建和部署GraphQL服务器

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Wikimedia Foundation 来接受捐赠。

介绍

GraphQL 于 2015 年由 Facebook 公开发布,作为 API 的查询语言,可以轻松查询和变异来自不同数据集合的数据。 从单个端点,您可以使用单个 POST 请求查询和改变多个数据源。 GraphQL 解决了 REST API 架构中的一些常见设计缺陷,例如端点返回的信息比您实际需要的信息多的情况。 此外,在使用 REST API 时,您可能需要向多个 REST 端点发送请求以收集您需要的所有信息——这种情况称为 n+1 问题。 例如,当您想要显示用户的信息,但需要从不同的端点收集个人详细信息和地址等数据时。

这些问题不适用于 GraphQL,因为它只有一个端点,可以从多个集合返回数据。 它返回的数据取决于您发送到此端点的 query。 在此查询中,您定义要接收的数据的结构,包括任何嵌套的数据集合。 除了查询之外,您还可以使用 mutation 来更改 GraphQL 服务器上的数据,并使用 subscription 来监视数据的更改。 更多关于 GraphQL 及其概念的信息,可以访问官网的【X71X】文档【X88X】。

由于 GraphQL 是一种具有很大灵活性的查询语言,它与 MongoDB 等基于文档的数据库结合得特别好。 这两种技术都基于分层的类型化模式,并且在 JavaScript 社区中很流行。 此外,MongoDB 的数据存储为 JSON 对象,因此无需在 GraphQL 服务器上进行额外的解析。

在本教程中,您将使用 Node.js 构建和部署一个 GraphQL 服务器,该服务器可以从运行在 Ubuntu 18.04 上的 MongoDB 数据库中查询和改变数据。 在本教程结束时,您将能够使用单个端点访问数据库中的数据,既可以通过终端直接向服务器发送请求,也可以使用预制的 GraphiQL 游乐场界面。 在这个 Playground 中,您可以通过发送查询、突变和订阅来探索 GraphQL 服务器的内容。 此外,您还可以找到为此服务器定义的模式的可视化表示。

在本教程结束时,您将使用 GraphiQL 操场与您的 GraphQL 服务器快速交互:

先决条件

在开始本指南之前,您需要以下内容:

第 1 步 — 设置 MongoDB 数据库

在创建 GraphQL 服务器之前,请确保您的数据库配置正确、启用了身份验证并填充了示例数据。 为此,您需要从命令提示符连接到运行 MongoDB 数据库的 Ubuntu 18.04 服务器。 本教程中的所有步骤都将在此服务器上进行。

建立连接后,运行以下命令检查 MongoDB 是否处于活动状态并在您的服务器上运行:

sudo systemctl status mongodb

您将在终端中看到以下输出,表明 MongoDB 数据库正在运行:

Output● mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2019-02-23 12:23:03 UTC; 1 months 13 days ago
     Docs: man:mongod(1)
 Main PID: 2388 (mongod)
    Tasks: 25 (limit: 1152)
   CGroup: /system.slice/mongodb.service
           └─2388 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf

在创建用于存储示例数据的数据库之前,您需要先创建一个 admin 用户,因为常规用户的范围仅限于特定数据库。 您可以通过执行以下打开 MongoDB shell 的命令来执行此操作:

mongo

使用 MongoDB shell,您可以直接访问 MongoDB 数据库,并可以创建用户或数据库并查询数据。 在这个 shell 中,执行以下命令,将新的 admin 用户添加到 MongoDB。 您可以用自己的用户名和密码组合替换突出显示的关键字,但不要忘记将它们写下来。

use admin
db.createUser({
    user: "admin_username",
    pwd: "admin_password",
    roles: [{ role: "root", db: "admin"}]
})

上述命令的第一行选择了名为 admin 的数据库,该数据库是存储所有管理员角色的数据库。 使用方法 db.createUser() 您可以创建实际用户并定义其用户名、密码和角色。

执行此命令将返回:

OutputSuccessfully added user: {
    "user" : "admin_username",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}

您现在可以通过键入 exit 来关闭 MongoDB shell。

接下来,再次登录 MongoDB shell,但这次使用新创建的 admin 用户:

mongo -u "admin_username" -p "admin_password" --authenticationDatabase "admin"

此命令将以特定用户身份打开 MongoDB shell,其中 -u 标志指定用户名, -p 标志指定该用户的密码。 额外的标志 --authenticationDatabase 指定您要以 admin 身份登录。

接下来,您将切换到一个新数据库,然后使用 db.createUser() 方法创建一个有权更改此数据库的新用户。 用您自己的信息替换突出显示的部分,确保记下这些凭据。

在 MongoDB shell 中运行以下命令:

use database_name
db.createUser({
    user: "username",
    pwd: "password",
    roles: ["readWrite"]
})

这将返回以下内容:

OutputSuccessfully added user: { "user" : "username", "roles" : ["readWrite"] }

创建数据库和用户后,用示例数据填充此数据库,这些数据可以在本教程后面的 GraphQL 服务器中查询。 为此,您可以使用 MongoDB 网站上的 bios 集合 示例。 通过执行以下代码片段中的命令,您将将此 bios 集合数据集的较小版本插入到您的数据库中。 您可以用您自己的信息替换突出显示的部分,但为了本教程的目的,将集合命名为 bios

db.bios.insertMany([
   {
       "_id" : 1,
       "name" : {
           "first" : "John",
           "last" : "Backus"
       },
       "birth" : ISODate("1924-12-03T05:00:00Z"),
       "death" : ISODate("2007-03-17T04:00:00Z"),
       "contribs" : [
           "Fortran",
           "ALGOL",
           "Backus-Naur Form",
           "FP"
       ],
       "awards" : [
           {
               "award" : "W.W. McDowell Award",
               "year" : 1967,
               "by" : "IEEE Computer Society"
           },
           {
               "award" : "National Medal of Science",
               "year" : 1975,
               "by" : "National Science Foundation"
           },
           {
               "award" : "Turing Award",
               "year" : 1977,
               "by" : "ACM"
           },
           {
               "award" : "Draper Prize",
               "year" : 1993,
               "by" : "National Academy of Engineering"
           }
       ]
   },
   {
       "_id" : ObjectId("51df07b094c6acd67e492f41"),
       "name" : {
           "first" : "John",
           "last" : "McCarthy"
       },
       "birth" : ISODate("1927-09-04T04:00:00Z"),
       "death" : ISODate("2011-12-24T05:00:00Z"),
       "contribs" : [
           "Lisp",
           "Artificial Intelligence",
           "ALGOL"
       ],
       "awards" : [
           {
               "award" : "Turing Award",
               "year" : 1971,
               "by" : "ACM"
           },
           {
               "award" : "Kyoto Prize",
               "year" : 1988,
               "by" : "Inamori Foundation"
           },
           {
               "award" : "National Medal of Science",
               "year" : 1990,
               "by" : "National Science Foundation"
           }
       ]
   }
]);

此代码块是一个由多个对象组成的数组,其中包含有关过去成功科学家的信息。 运行这些命令将此集合输入数据库后,您将收到以下消息,指示数据已添加:

Output{
    "acknowledged" : true,
    "insertedIds" : [
        1,
        ObjectId("51df07b094c6acd67e492f41")
    ]
}

看到成功消息后,您可以通过键入 exit 关闭 MongoDB shell。 接下来,将 MongoDB 安装配置为启用授权,以便只有经过身份验证的用户才能访问数据。 要编辑 MongoDB 安装的配置,请打开包含此安装设置的文件:

sudo nano /etc/mongodb.conf

取消注释以下代码中突出显示的行以启用授权:

/etc/mongodb.conf

...
# Turn on/off security.  Off is currently the default
#noauth = true
auth = true
...

为了使这些更改生效,请运行以下命令重新启动 MongoDB:

sudo systemctl restart mongodb

通过执行以下命令确保数据库再次运行:

sudo systemctl status mongodb

这将产生类似于以下内容的输出:

Output● mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2019-02-23 12:23:03 UTC; 1 months 13 days ago
     Docs: man:mongod(1)
 Main PID: 2388 (mongod)
    Tasks: 25 (limit: 1152)
   CGroup: /system.slice/mongodb.service
           └─2388 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf

要确保您的用户可以连接到您刚刚创建的数据库,请尝试使用以下命令以经过身份验证的用户身份打开 MongoDB shell:

mongo -u "username" -p "password" --authenticationDatabase "database_name"

这使用与以前相同的标志,只是这次 --authenticationDatabase 设置为您创建的数据库并填充了示例数据。

现在您已经成功添加了一个 admin 用户和另一个对包含示例数据的数据库具有读/写访问权限的用户。 此外,数据库启用了授权,这意味着您需要用户名和密码才能访问它。 在下一步中,您将创建将在本教程稍后部分连接到此数据库的 GraphQL 服务器。

第 2 步 — 创建 GraphQL 服务器

数据库配置并填充了示例数据后,是时候创建一个可以查询和改变这些数据的 GraphQL 服务器了。 为此,您将使用 Expressexpress-graphql,它们都在 Node.js 上运行。 Express 是一个轻量级框架,可以快速搭建 Node.js HTTP 服务器,express-graphql 提供中间件,让快速搭建 GraphQL 服务器成为可能。

第一步是确保您的机器是最新的:

sudo apt update

接下来,通过运行以下命令在您的服务器上安装 Node.js。 与 Node.js 一起,您还将安装 npm,这是一个在 Node.js 上运行的 JavaScript 包管理器。

sudo apt install nodejs npm

安装完之后,检查你刚刚安装的Node.js版本是否为v8.10.0或更高版本:

node -v

这将返回以下内容:

Outputv8.10.0

要初始化一个新的 JavaScript 项目,请以 sudo 用户身份在服务器上运行以下命令,并将突出显示的关键字替换为您的项目名称。

首先进入服务器的根目录:

cd

在那里,创建一个以您的项目命名的新目录:

mkdir project_name

移动到这个目录:

cd project_name 

最后,使用以下命令初始化一个新的 npm 包:

sudo npm init -y

运行 npm init -y 后,您将收到一条成功消息,表明已创建以下 package.json 文件:

OutputWrote to /home/username/project_name/package.json:

{
  "name": "project_name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

注意:你也可以不带-y标志执行npm init,然后回答多个问题来设置项目名称、作者等。 您可以输入详细信息或只需按 Enter 键继续。


现在您已经初始化了项目,请安装设置 GraphQL 服务器所需的包:

sudo npm install --save express express-graphql graphql

创建一个名为 index.js 的新文件,然后通过运行以下命令打开此文件:

sudo nano index.js

接下来,将以下代码块添加到新创建的文件中以设置 GraphQL 服务器:

index.js

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

// Provide resolver functions for your schema fields
const resolvers = {
  hello: () => 'Hello world!'
};

const app = express();
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: resolvers
}));
app.listen(4000);

console.log(`🚀 Server ready at http://localhost:4000/graphql`);

该代码块由几个非常重要的部分组成。 首先,您描述 GraphQL API 返回的数据架构:

index.js

...
// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    hello: String
  }
`);
...

Query 类型定义了可以执行的查询以及返回结果的格式。 如您所见,唯一定义的查询是 hello,它以 String 格式返回数据。

下一部分建立 解析器 ,其中数据与您可以查询的模式匹配:

index.js

...
// Provide resolver functions for your schema fields
const resolvers = {
  hello: () => 'Hello world!'
};
...

这些解析器直接链接到模式,并返回与这些模式匹配的数据。

此代码块的最后一部分初始化 GraphQL 服务器,使用 Express 创建 API 端点,并描述运行 GraphQL 端点的端口:

index.js

...
const app = express();
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: resolvers
}));
app.listen(4000);

console.log(`🚀 Server ready at http://localhost:4000/graphql`);

添加这些行后,保存并退出 index.js

接下来,要实际运行 GraphQL 服务器,您需要使用 Node.js 运行文件 index.js。 这可以从命令行手动完成,但通常的做法是设置 package.json 文件来为您执行此操作。

打开package.json文件:

sudo nano package.json

将以下突出显示的行添加到此文件中:

包.json

{
  "name": "project_name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

保存并退出文件。

要启动 GraphQL 服务器,请在终端中执行以下命令:

npm start

运行此命令后,终端提示将消失,并显示一条消息以确认 GraphQL 服务器正在运行:

Output🚀 Server ready at http://localhost:4000/graphql

如果您现在打开另一个终端会话,您可以通过执行以下命令来测试 GraphQL 服务器是否正在运行。 这会在包含您的 GraphQL 查询的 --data 标志之后发送带有 JSON 正文的 curl POST 请求到本地端点:

curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ hello }" }' http://localhost:4000/graphql

这将执行代码中 GraphQL 模式中描述的查询,并以可预测的 JSON 格式返回数据,该格式与解析器中返回的数据相同:

Output{ "data": { "hello": "Hello world!" } }

注意:如果Express服务器崩溃或卡住,您需要手动杀死服务器上正在运行的node进程。 要杀死所有此类进程,您可以执行以下命令:

killall node

之后,您可以通过运行以下命令重新启动 GraphQL 服务器:

npm start

在此步骤中,您创建了第一个版本的 GraphQL 服务器,该服务器现在运行在可以在您的服务器上访问的本地端点上。 接下来,您将解析器连接到 MongoDB 数据库。

第 3 步 - 连接到 MongoDB 数据库

按顺序使用 GraphQL 服务器,您现在可以设置与之前配置并填充数据的 MongoDB 数据库的连接,并创建与该数据匹配的新模式。

为了能够从 GraphQL 服务器连接到 MongoDB,请从 npm 安装 MongoDB 的 JavaScript 包:

sudo npm install --save mongodb

安装完成后,在文本编辑器中打开 index.js

sudo nano index.js

接下来,在导入的依赖项之后将以下突出显示的代码添加到 index.js 中,并使用您自己与本地 MongoDB 数据库的连接详细信息填充突出显示的值。 usernamepassworddatabase_name 是您在本教程的第一步中创建的。

index.js

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const { MongoClient } = require('mongodb');

const context = () => MongoClient.connect('mongodb://username:password@localhost:27017/database_name', { useNewUrlParser: true }).then(client => client.db('database_name'));
...

这些行将与本地 MongoDB 数据库的连接添加到名为 context 的函数中。 每个解析器都可以使用此上下文功能,这就是您使用它来设置数据库连接的原因。

接下来,在您的 index.js 文件中,通过插入以下突出显示的行,将上下文函数添加到 GraphQL 服务器的初始化中:

index.js

...
const app = express();
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: resolvers,
  context
}));
app.listen(4000);

console.log(`🚀 Server ready at http://localhost:4000/graphql`);

现在您可以从解析器中调用此上下文函数,从而从 MongoDB 数据库中读取变量。 如果您回顾本教程的第一步,您可以看到数据库中存在哪些值。 从这里,定义一个与此数据结构匹配的新 GraphQL 模式。 用以下突出显示的行覆盖常量 schema 的先前值:

index.js

...
// Construct a schema, using GrahQL schema language
const schema = buildSchema(`
  type Query {
    bios: [Bio]
  }
  type Bio {
    name: Name,
    title: String,
    birth: String,
    death: String,
    awards: [Award]
  }
  type Name {
    first: String,
    last: String
  },
  type Award {
    award: String,
    year: Float,
    by: String
  }
`);
...

Query 类型已更改,现在返回新类型 Bio 的集合。 这种新类型由多种类型组成,包括另外两种非标量类型 NameAwards,这意味着这些类型与 String 或 等预定义格式不匹配X176X]。 有关定义 GraphQL 模式的更多信息,您可以查看 GraphQL 的 文档

此外,由于解析器将数据库中的数据绑定到架构,因此在您更改架构时更新解析器的代码。 创建一个名为 bios 的新解析器,它等于可以在架构中找到的 Query 和数据库中集合的名称。 请注意,在这种情况下,db.collection('bios') 中的集合名称为 bios,但如果您为集合分配了不同的名称,这将改变。

将以下突出显示的行添加到 index.js

index.js

...
// Provide resolver functions for your schema fields
const resolvers = {
  bios: (args, context) => context().then(db => db.collection('bios').find().toArray())
};
...

此函数将使用 context 函数,您可以使用该函数从 MongoDB 数据库中检索变量。 对代码进行这些更改后,保存并退出 index.js

为了使这些更改生效,您需要重新启动 GraphQL 服务器。 您可以使用键盘组合 CTRL + C 停止当前进程,并通过运行以下命令启动 GraphQL 服务器:

npm start

现在您可以使用更新后的模式并查询数据库内的数据。 如果您查看架构,您会看到 biosQuery 返回类型 Bio; 此类型也可以返回类型 Name

要返回数据库中所有 bios 的所有名字和姓氏,请在新的终端窗口中向 GraphQL 服务器发送以下请求:

 curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ bios { name { first, last } } }" }' http://localhost:4000/graphql

这将再次返回一个与模式结构匹配的 JSON 对象:

Output{"data":{"bios":[{"name":{"first":"John","last":"Backus"}},{"name":{"first":"John","last":"McCarthy"}}]}}

通过使用 Bio 类型中描述的任何类型扩展查询,您可以轻松地从 bios 中检索更多变量。

此外,您可以通过指定 id 来检索简历。 为此,您需要向 Query 类型添加另一种类型并扩展解析器。 为此,请在文本编辑器中打开 index.js

sudo nano index.js

添加以下突出显示的代码行:

index.js

...
// Construct a schema, using GrahQL schema language
const schema = buildSchema(`
  type Query {
    bios: [Bio]
    bio(id: Int): Bio
  }

  ...

  // Provide resolver functions for your schema fields
  const resolvers = {
    bios: (args, context) => context().then(db => db.collection('bios').find().toArray()),
    bio: (args, context) => context().then(db => db.collection('bios').findOne({ _id: args.id }))
  };
  ...

保存并退出文件。

在运行 GraphQL 服务器的终端中,按 CTRL + C 停止运行,然后执行以下命令重新启动它:

npm start

在另一个终端窗口中,执行以下 GraphQL 请求:

curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ bio(id: 1) { name { first, last } } }" }' http://localhost:4000/graphql

这将返回 id 等于 1 的 bio 条目:

Output{ "data": { "bio": { "name": { "first": "John", "last": "Backus" } } } }

能够从数据库中查询数据并不是 GraphQL 的唯一功能。 您还可以更改数据库中的数据。 为此,打开 index.js

sudo nano index.js

在类型 Query 旁边,您还可以使用类型 Mutation,它允许您对数据库进行变异。 要使用此类型,请将其添加到架构中,并通过插入这些突出显示的行来创建输入类型:

index.js

...
// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    bios: [Bio]
    bio(id: Int): Bio
  }
  type Mutation {
    addBio(input: BioInput) : Bio
  }
  input BioInput {
    name: NameInput
    title: String
    birth: String
    death: String
  }
  input NameInput {
    first: String
    last: String
  }
...

这些输入类型定义了哪些变量可以用作输入,您可以在解析器中访问这些变量并用于在数据库中插入新文档。 通过将以下行添加到 index.js 来执行此操作:

index.js

...
// Provide resolver functions for your schema fields
const resolvers = {
  bios: (args, context) => context().then(db => db.collection('bios').find().toArray()),
  bio: (args, context) => context().then(db => db.collection('bios').findOne({ _id: args.id })),
  addBio: (args, context) => context().then(db => db.collection('bios').insertOne({ name: args.input.name, title: args.input.title, death: args.input.death, birth: args.input.birth})).then(response => response.ops[0])
};
...

与常规查询的解析器一样,您需要从 index.js 中的解析器返回一个值。 在 Mutation 类型 Bio 发生变异的情况下,您将返回变异生物的值。

此时,您的 index.js 文件将包含以下几行:

index.js

iconst express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const { MongoClient } = require('mongodb');

const context = () => MongoClient.connect('mongodb://username:password@localhost:27017/database_name', { useNewUrlParser: true })
  .then(client => client.db('GraphQL_Test'));

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    bios: [Bio]
    bio(id: Int): Bio
  }
  type Mutation {
    addBio(input: BioInput) : Bio
  }
  input BioInput {
    name: NameInput
    title: String
    birth: String
    death: String
  }
  input NameInput {
    first: String
    last: String
  }
  type Bio {
    name: Name,
    title: String,
    birth: String,
    death: String,
    awards: [Award]
  }
  type Name {
    first: String,
    last: String
  },
  type Award {
    award: String,
    year: Float,
    by: String
  }
`);

// Provide resolver functions for your schema fields
const resolvers = {
  bios: (args, context) =>context().then(db => db.collection('Sample_Data').find().toArray()),
  bio: (args, context) =>context().then(db => db.collection('Sample_Data').findOne({ _id: args.id })),
  addBio: (args, context) => context().then(db => db.collection('Sample_Data').insertOne({ name: args.input.name, title: args.input.title, death: args.input.death, birth: args.input.birth})).then(response => response.ops[0])
};

const app = express();
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: resolvers,
  context
}));
app.listen(4000);

console.log(`🚀 Server ready at http://localhost:4000/graphql`);

保存并退出index.js

要检查您的新突变是否正常工作,请通过按 CTRL + c 并在运行 GraphQL 服务器的终端中运行 npm start 重新启动 GraphQL 服务器,然后打开另一个终端会话执行以下 curl 请求。 就像 curl 查询请求一样,--data 标志中的正文将被发送到 GraphQL 服务器。 突出显示的部分将添加到数据库中:

curl -X POST -H "Content-Type: application/json" --data '{ "query": "mutation { addBio(input: { name: { first: \"test\", last: \"user\" } }) { name { first, last } } }" }' http://localhost:4000/graphql

这将返回以下结果,这意味着您刚刚向数据库中插入了一个新的 bio:

Output{ "data": { "addBio": { "name": { "first": "test", "last": "user" } } } }

在此步骤中,您创建了与 MongoDB 和 GraphQL 服务器的连接,允许您通过执行 GraphQL 查询从该数据库中检索和更改数据。 接下来,您将公开此 GraphQL 服务器以进行远程访问。

第 4 步 — 允许远程访问

设置好数据库和 GraphQL 服务器后,您现在可以配置 GraphQL 服务器以允许远程访问。 为此,您将使用在先决条件教程 如何在 Ubuntu 18.04 上安装 Nginx 中设置的 Nginx。 此 Nginx 配置可以在 /etc/nginx/sites-available/example.com 文件中找到,其中 example.com 是您在先决条件教程中添加的服务器名称。

打开此文件进行编辑,将您的域名替换为 example.com

sudo nano /etc/nginx/sites-available/example.com

在此文件中,您可以找到一个侦听端口 80 的服务器块,您已经在先决条件教程中为 server_name 设置了一个值。 在此服务器块中,将 root 的值更改为您为 GraphQL 服务器创建代码的目录,并添加 index.js 作为索引。 此外,在 location 块中,设置 proxy_pass 以便您可以使用服务器的 IP 或自定义域名来引用 GraphQL 服务器:

/etc/nginx/sites-available/example.com

server {
  listen 80;
  listen [::]:80;

  root /project_name;
  index index.js;

  server_name example.com;

  location / {
    proxy_pass http://localhost:4000/graphql;
  }
}

通过运行确保此配置文件中没有 Nginx 语法错误:

sudo nginx -t

您将收到以下输出:

Outputnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

当配置文件没有发现错误时,重启 Nginx:

sudo systemctl restart nginx

现在,您可以通过执行 example.com 并将其替换为您的服务器的 IP 或您的自定义域名,从任何终端会话选项卡访问您的 GraphQL 服务器:

curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ bios { name { first, last } } }" }' http://example.com

这将返回与上一步相同的 JSON 对象,包括您可能使用突变添加的任何其他数据:

Output{"data":{"bios":[{"name":{"first":"John","last":"Backus"}},{"name":{"first":"John","last":"McCarthy"}},{"name":{"first":"test","last":"user"}}]}}

现在您已经使您的 GraphQL 服务器可以远程访问,请确保您的 GraphQL 服务器在您关闭终端或服务器重新启动时不会关闭。 这样,只要您想发出请求,就可以通过 GraphQL 服务器访问您的 MongoDB 数据库。

为此,请使用 npm 包 forever,这是一个 CLI 工具,可确保您的命令行脚本连续运行,或在出现任何故障时重新启动。

使用 npm 安装 forever

sudo npm install forever -g

安装完成后,将其添加到 package.json 文件中:

包.json

{
  "name": "project_name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "deploy": "forever start --minUptime 2000 --spinSleepTime 5 index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ...

要在启用 forever 的情况下启动 GraphQL 服务器,请运行以下命令:

npm run deploy

这将使用 forever 启动包含 GraphQL 服务器的 index.js 文件,并确保它以至少 2000 毫秒的正常运行时间和每次重启之间 5 毫秒的最小正常运行时间保持运行,以防万一发生故障。 GraphQL 服务器现在将在后台持续运行,因此当您想向服务器发送请求时,无需再打开新选项卡。

您现在已经创建了一个使用 MongoDB 存储数据并设置为允许从远程服务器访问的 GraphQL 服务器。 在下一步中,您将启用 GraphiQL 游乐场,这将使您更容易检查 GraphQL 服务器。

第 5 步 — 启用 GraphiQL Playground

能够将 cURL 请求发送到 GraphQL 服务器是很棒的,但是拥有一个可以立即执行 GraphQL 请求的用户界面会更快,尤其是在开发过程中。 为此,您可以使用 GraphiQL,这是包 express-graphql 支持的接口。

要启用 GraphiQL,请编辑文件 index.js

sudo nano index.js

添加以下突出显示的行:

index.js

const app = express();
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: resolvers,
  context,
  graphiql: true
}));
app.listen(4000);

console.log(`🚀 Server ready at http://localhost:4000/graphql`);

保存并退出文件。

为了使这些更改可见,请确保通过执行以下命令停止 forever

forever stop index.js

接下来,再次启动 forever 以便运行最新版本的 GraphQL 服务器:

npm run deploy

在 URL http://example.com 上打开浏览器,将 example.com 替换为您的域名或服务器 IP。 您将看到 GraphiQL 游乐场,您可以在其中键入 GraphQL 请求。

在这个 Playground 的左侧,您可以输入 GraphQL 查询和突变,而输出将显示在 Playground 的右侧。 要测试这是否有效,请在左侧键入以下查询:

query {
  bios {
    name {
      first
      last
    }
  }
}

这将在操场的右侧输出相同的结果,再次以 JSON 格式:

现在您可以使用终端和 GraphiQL 游乐场发送 GraphQL 请求。

结论

在本教程中,您已经设置了一个 MongoDB 数据库,并使用 GraphQL、Node.js 和 Express 用于服务器从该数据库中检索和变异数据。 此外,您将 Nginx 配置为允许远程访问此服务器。 您不仅可以直接向此 GraphQL 服务器发送请求,还可以将 GraphiQL 用作浏览器内的可视化 GraphQL 界面。

如果您想了解 GraphQL,可以在 NDC {London} 观看我在 GraphQL 上的演示文稿的 recording 或访问网站 howtographql.com 获取教程关于 GraphQL。 要研究 GraphQL 如何与其他技术交互,请查看 如何在 Ubuntu 18.04 上手动设置 Prisma 服务器的教程,有关使用 MongoDB 构建应用程序的更多信息,请参阅 如何构建包含 Nest.js、MongoDB 和 Vue.js 的博客。