什么是 GraphQL 以及如何使用它?什么是 GraphQL?先决条件:如何在 Node.js 代码中使用 GraphQL?测试应用程序。恭喜😃

2025-05-24

什么是 GraphQL 以及如何使用它

什么是 GraphQL?

先决条件

如何在 Node.js 中使用 GraphQL

代码

测试应用程序

恭喜😃

这篇文章最初发表于adityasridhar.com

什么是 GraphQL?

它基本上是一种 API 的查询语言

GraphQL 显示服务器提供的不同类型数据,然后客户端可以准确地选择它想要的数据。

另外,在 GraphQL 中,您可以在一次调用中获取多个服务器资源,而不必进行多个 REST API 调用。

您可以查看https://graphql.org/以获取完整的好处列表。

问题是,除非你亲眼看到 GraphQL 的实际应用,否则很难理解它的好处。所以,让我们开始使用 GraphQL 吧。

在本文中,我们将使用 GraphQL 和 NodeJS。

先决条件

从https://nodejs.org/en/安装 NodeJS

如何在 Node.js 中使用 GraphQL

GraphQL 可以与多种语言一起使用。本文我们将重点介绍如何在 NodeJS 中使用 GraphQL 和 JavaScript。

创建一个名为graphql-with-nodejs 的文件夹。进入项目文件夹并运行npm init以创建 NodeJS 项目。相关命令如下。

cd graphql-with-nodejs
npm init
Enter fullscreen mode Exit fullscreen mode

安装依赖项

使用以下命令安装 Express

npm install express
Enter fullscreen mode Exit fullscreen mode

使用以下命令安装 GraphQL。我们将安装 graphql 和 express 版 graphql。

npm install express-graphql graphql
Enter fullscreen mode Exit fullscreen mode

NodeJS 代码

在项目内创建一个名为server.js 的文件,并将以下代码复制到其中

const express = require('express');
const port = 5000;
const app = express();

app.get('/hello', (req,res) => {
    res.send("hello");
   }
);

app.listen(port);
console.log(`Server Running at localhost:${port}`);
Enter fullscreen mode Exit fullscreen mode

上面的代码有一个名为/hello 的http get 端点。

终点是使用 express 创建的。

现在让我们修改此代码以启用 GraphQL。

在代码中启用 GraphQL

GraphQL 将有一个名为/graphql 的单个 url 端点,它将处理所有请求。

将以下代码复制到server.js中

//get all the libraries needed
const express = require('express');
const graphqlHTTP = require('express-graphql');
const {GraphQLSchema} = require('graphql');

const {queryType} = require('./query.js');

//setting up the port number and express app
const port = 5000;
const app = express();

 // Define the Schema
const schema = new GraphQLSchema({ query: queryType });

//Setup the nodejs GraphQL server
app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true,
}));

app.listen(port);
console.log(`GraphQL Server Running at localhost:${port}`);
Enter fullscreen mode Exit fullscreen mode

现在让我们来看一下这段代码

graphqlHTTP使我们能够在/graphql url 上设置一个 GraphQL 服务器。它基本上知道如何处理传入的请求。

此设置通过以下代码行完成

app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true,
}));
Enter fullscreen mode Exit fullscreen mode

现在让我们探索 graphqlHTTP 内部的参数

graphiql

graphiql 是一个 Web UI,你可以用它来测试 graphql 端点。我们将它设置为 true,以便更轻松地测试我们创建的各种 graphql 端点。

模式

虽然 graphql 只有一个外部端点/graphql,但它可以有多个其他端点来执行各种操作。这些端点将在 schema 中指定。

该模式将执行以下操作:

  • 指定端点
  • 指示端点的输入和输出字段
  • 指示当到达端点时应该采取什么行动等等。

Schema 在代码中定义如下

const schema = new GraphQLSchema({ query: queryType });
Enter fullscreen mode Exit fullscreen mode

模式可以包含查询类型突变类型。本文仅关注查询类型。

询问

从模式中可以看出,查询已设置为queryType

我们使用以下命令从query.js文件导入 queryType

const {queryType} = require('./query.js');
Enter fullscreen mode Exit fullscreen mode

query.js是一个自定义文件,我们将很快创建它。

查询是我们在模式中指定只读端点的地方。

在项目中创建一个名为query.js的文件,并将以下代码复制到其中。

const { GraphQLObjectType,
    GraphQLString
} = require('graphql');


//Define the Query
const queryType = new GraphQLObjectType({
    name: 'Query',
    fields: {
        hello: {
            type: GraphQLString,

            resolve: function () {
                return "Hello World";
            }
        }
    }
});

exports.queryType = queryType;
Enter fullscreen mode Exit fullscreen mode

查询解释

queryType 被创建为GraphQLObjectType并被赋予名称Query

字段是我们指定各种端点的地方。

因此,我们在这里添加一个名为hello的端点

hello类型GraphQLString,这意味着此端点的返回类型为 String。由于这是一个 graphql schema,因此返回类型是GraphQLString而不是String。因此直接使用 String 是行不通的。

resolve函数表示调用端点时要执行的操作。此处的操作是返回一个字符串“Hello World”。

最后,我们使用 导出查询类型exports.queryType = queryType。这是为了确保我们可以在server.js中导入它。

运行应用程序

使用以下命令运行应用程序

node server.js
Enter fullscreen mode Exit fullscreen mode

该应用程序在localhost:5000/graphql上运行

您可以通过访问 localhost:5000/graphql 来测试该应用程序。

此 URL 运行 Graphiql Web UI,如下面的屏幕所示。

graphiql

左侧给出输入,右侧显示输出。

给出以下输入

{
  hello
}
Enter fullscreen mode Exit fullscreen mode

这将给出以下输出

{
  "data": {
    "hello": "Hello World"
  }
}
Enter fullscreen mode Exit fullscreen mode

恭喜😃

您已创建第一个 GraphQL 端点。

添加更多端点

我们将创建 2 个新端点:

  • movie:此端点将返回一部电影,给定电影 ID
  • 导演:此端点将根据导演 ID 返回导演。它还将返回该导演执导的所有电影。

添加数据

通常,应用程序会从数据库读取数据。但在本教程中,为了简单起见,我们将在代码中对数据进行硬编码。

创建一个名为data.js的文件并添加以下代码。

//Hardcode some data for movies and directors
let movies = [{
    id: 1,
    name: "Movie 1",
    year: 2018,
    directorId: 1
},
{
    id: 2,
    name: "Movie 2",
    year: 2017,
    directorId: 1
},
{
    id: 3,
    name: "Movie 3",
    year: 2016,
    directorId: 3
}
];

let directors = [{
    id: 1,
    name: "Director 1",
    age: 20
},
{
    id: 2,
    name: "Director 2",
    age: 30
},
{
    id: 3,
    name: "Director 3",
    age: 40
}
];

exports.movies = movies;
exports.directors = directors;
Enter fullscreen mode Exit fullscreen mode

此文件包含电影和导演数据。我们将使用此文件中的数据作为我们的端点。

将电影端点添加到查询中

新的端点将被添加到 query.js 文件中的 queryType

电影端点的代码如下所示

movie: {
            type: movieType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(movies, { id: args.id });
            }
        }
Enter fullscreen mode Exit fullscreen mode

此端点的返回类型是movieType,我们将很快定义它。

args参数用于指示影片端点的输入。此端点的输入是id,其类型为
GraphQLInt。

resolve函数从电影列表中返回与 id 对应的电影。findlodash库中的一个函数,用于在列表中查找元素。

query.js的完整代码如下所示

const { GraphQLObjectType,
    GraphQLString,
    GraphQLInt
} = require('graphql');
const _ = require('lodash');

const {movieType} = require('./types.js');
let {movies} = require('./data.js');


//Define the Query
const queryType = new GraphQLObjectType({
    name: 'Query',
    fields: {
        hello: {
            type: GraphQLString,

            resolve: function () {
                return "Hello World";
            }
        },

        movie: {
            type: movieType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(movies, { id: args.id });
            }
        }
    }
});

exports.queryType = queryType;
Enter fullscreen mode Exit fullscreen mode

从上面的代码可以看出,movieType实际上是在types.js中定义的

添加自定义类型 movieType

创建一个名为types.js的文件。

在 types.js 中添加以下代码

const {
    GraphQLObjectType,
    GraphQLID,
    GraphQLString,
    GraphQLInt
} = require('graphql');

// Define Movie Type
movieType = new GraphQLObjectType({
    name: 'Movie',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        year: { type: GraphQLInt },
        directorId: { type: GraphQLID }

    }
});

exports.movieType = movieType;
Enter fullscreen mode Exit fullscreen mode

可以看出,movieType被创建为GraphQLObjectType

它有 4 个字段:id、name、year 和 directorId。添加每个字段时,也会指定它们的类型。

这些字段直接来自数据。在本例中,它来自电影列表。

添加主管端点的查询和类型

与电影类似,甚至可以添加导演端点。

query.js中,可以按如下方式添加 director 端点

director: {
            type: directorType,
            args: {
                id: { type: GraphQLInt }
            },
            resolve: function (source, args) {
                return _.find(directors, { id: args.id });
            }
        }
Enter fullscreen mode Exit fullscreen mode

directorType可以在types.js中添加如下内容

//Define Director Type
directorType = new GraphQLObjectType({
    name: 'Director',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        age: { type: GraphQLInt },
        movies: {
            type: new GraphQLList(movieType),
            resolve(source, args) {
                return _.filter(movies, { directorId: source.id });
            }

        }

    }
});
Enter fullscreen mode Exit fullscreen mode

等一下。directorType和 movieType有点不同。这是为什么呢?

为什么directorType中有一个 resolve 函数?之前我们看到 resolve 函数只存在于查询中。

导演类型的特殊性

当调用导演端点时,我们必须返回导演的详细信息,以及该导演执导的所有电影。

directorType中的前 3 个字段id、name、age很简单,直接来自数据(导演列表)

第四个字段movies需要包含该导演的电影列表。

为此,我们要提到电影字段的类型
movieType 的 GraphQLList(电影列表)

但究竟如何才能找到这位导演执导的所有电影呢?

为此,我们在 movies 字段中设置了一个resolve
函数。 该 resolve 函数的输入是sourceargs

源将具有父对象详细信息。

假设导演的字段id = 1,name = "Random",age = 20。那么source.id = 1,source.name = "Random",source.age = 20

因此在这个例子中,resolve 函数找出所有 directorId 与所需导演的 Id 匹配的电影。

代码

此应用程序的完整代码可在此GitHub 仓库中找到

测试应用程序

现在让我们针对不同的场景测试该应用程序。

使用运行应用程序node server.js

转到localhost:5000/graphql并尝试以下输入。

电影

输入:

{
  movie(id: 1) {
    name
  }
}
Enter fullscreen mode Exit fullscreen mode

输出:

{
  "data": {
    "movie": {
      "name": "Movie 1"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

从上面可以看出,客户端可以精确地请求它想要的内容,GraphQL 将确保只返回这些参数。这里只请求了name字段,服务器也只返回了该字段。

在 中movie(id: 1),id 是输入参数。我们要求服务器返回 id 为 1 的电影。

输入:

{
  movie(id: 3) {
    name
    id
    year
  }
}
Enter fullscreen mode Exit fullscreen mode

输出:

{
  "data": {
    "movie": {
      "name": "Movie 3",
      "id": "3",
      "year": 2016
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,请求了name、id 和 year字段。因此服务器返回了所有这些字段。

导演

输入:

{
  director(id: 1) {
    name
    id,
    age
  }
}
Enter fullscreen mode Exit fullscreen mode

输出:

{
  "data": {
    "director": {
      "name": "Director 1",
      "id": "1",
      "age": 20
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

输入:

{
  director(id: 1) {
    name
    id,
    age,
    movies{
      name,
      year
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

输出:

{
  "data": {
    "director": {
      "name": "Director 1",
      "id": "1",
      "age": 20,
      "movies": [
        {
          "name": "Movie 1",
          "year": 2018
        },
        {
          "name": "Movie 2",
          "year": 2017
        }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们展示了 GraphQL 的强大功能。我们指定了 id 为 1 的导演,并指定了这位导演的所有电影。导演和电影字段都是完全可自定义的,客户端可以精确地请求所需的内容。

类似地,这可以扩展到其他字段和类型。例如,我们可以运行类似“查找 ID 为 1 的导演”的查询。查找该导演的所有电影。查找每部电影的演员。查找每位演员的评分最高的 5 部电影,等等。对于此查询,我们需要指定类型之间的关系。完成此操作后,客户端可以查询所需的任何关系。

恭喜😃

现在您已经了解了 GraphQL 的基本概念。

您可以查看文档以了解有关 GraphQL 的更多信息

欢迎随时通过LinkedIn与我联系或在Twitter上关注我。

如果您喜欢这篇文章,您可以访问我的网站https://adityasridhar.com查看其他类似的文章

文章来源:https://dev.to/adityasridhar/what-is-graphql-and-how-to-use-it-1f58
PREV
Vue 速查表 1 目录
NEXT
如何高效使用 git Git 工作流 Git 中的开发流程 参考文献 恭喜😄