graphql node mysql_GraphQL 简介:原理及其使用

GraphQL 是 API 的查询语言,它显示了服务器提供的不同类型的数据,然后客户端可以准确地选择它想要的内容。

同样在 GraphQL 中,你可以一次性调用多个服务器资源,而不再需要进行多个 REST API 调用。

你可以通过访问 https://graphql.org/ 来了解 GraphQL 的所有优点。我们必须在实践中使用 GraphQL,否则你很难理解它的优点,那么现在就让我们开始使用 GraphQL 吧~

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

先决条件

如何将 GraphQL 与 NodeJs 一起使用?

GraphQL 可以与多种语言一起使用,这篇文章中,我们将重点介绍如何通过 NodeJS 将 GraphQL 与 JavaScript 结合使用。

新建一个名为 graphql-with-nodejs 的文件夹,进入项目文件夹并运行 npm init 来创建 NodeJS 项目,终端命令如下:

cd graphql-with-nodejs

npm init

安装依赖项

使用以下命令安装 Express:

npm install express

我们将使用以下命令安装 GraphQL 和 GraphQL for Express:

npm install express-graphql graphql

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}`);

上面的代码有一个名为 /hello 的 HTTP GET 请求,这个请求是使用 Express 创建的。现在,让我们修改此代码来启用 GraphQL。

在代码中启用 GraphQL

GraphQL 有一个名为 /graphql 的单一的 URL 资源路径,它将处理所有的请求。

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

//get all the libraries neededconst express = require("express");

const graphqlHTTP = require("express-graphql");

const { GraphQLSchema } = require("graphql");

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

//setting up the port number and express appconst port = 5000;

const app = express();

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

//Setup the nodejs GraphQL serverapp.use(

"/graphql",

graphqlHTTP({

schema: schema,

graphiql: true

})

);

app.listen(port);

console.log(`GraphQL Server Running at localhost:${port}`);

现在让我们来看看这段代码吧~

graphqlHTTP 使我们能够在 /graphql url 中设置 GraphQL 服务器,它知道如何处理即将发生的请求。这个设置在以下代码行中完成:

app.use(

"/graphql",

graphqlHTTP({

schema: schema,

graphiql: true

})

);

现在,让我们一起来探索 graphqlHTTP 中的参数吧~

graphiql

graphiql 是一个 Web UI,您可以使用它来测试 GraphQL 资源路径。我们将其设置为 true,以便更容易测试我们创建的各种 GraphQL 请求路径。

schema

GraphQL 有一个外部资源路径 /graphql,这个资源路径可以有多个其他资源路径执行各种操作,这些资源路径可以在 schema 中被指定。

schema 将执行以下操作:指定资源路径

指示资源路径的输入和输出字段

指示在命中资源路径时应执行的操作,依此类推

schema 在代码中定义如下:

const schema = new GraphQLSchema({ query: queryType });

schema 可以包含 Query 和 Mutation 类型,但是这篇文章将仅关注 Query类型。

查询(query)

你可以在 schema 中看到查询已设置为 queryType,我们使用以下命令从 query.js 文件中导入 queryType:

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

query.js 是我们即将创建的自定义文件,query 是我们在 schema 中指定只读请求路径的地方。

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

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

//Define the Queryconst queryType = new GraphQLObjectType({

name: "Query",

fields: {

hello: {

type: GraphQLString,

resolve: function() {

return "Hello World";

}

}

}

});

exports.queryType = queryType;

查询说明

queryType 创建为 GraphQLObjectType 并命名为 Query。fields 是我们指定各种资源路径的地方,因此我们在这里添加一个名为 hello 的资源路径,hello 有一个 GraphQLString 类型,这意味着该资源路径的返回类型为 String。这里的类型是 GraphQLString 而不是 String,因为这是 GraphQL scheme,因此直接使用 String 是不行的。

resolve 函数表示调用请求时要执行的操作,这里的操作是返回一个字符串 Hello World。

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

运行应用程序

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

node server.js

你可以通过访问 localhost:5000/graphql 本地运行和测试该程序。

此 URL 在 Graphiql Web UI 中运行,如下图所示:

左边输入相应查询,右边为相应的输出,输入以下查询:

{

hello;

}

对应的输出如下:

{

"data": {

"hello": "Hello World"

}

}

恭喜你!

你已经创建了第一个 GraphQL 资源路径。

添加更多资源路径

我们将会创建 2 个新的资源路径:movie:这个资源路径将会返回指定 ID 的电影

director:这个资源路径将返回指定 ID 的导演,还将返回该导演指导的所有电影。

添加数据

通常,一个应用程序将从数据库中读取数据,但是在本教程中,我们将简单地对代码本身中的数据进行硬编码。

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

//Hardcode some data for movies and directorslet 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;

此文件包含 movies 和 directors 数据,我们将使用此文件中的数据作为我们请求所需的数据。

将 movie 资源路径添加到查询中

新的资源路径将被添加到 query.js 文件中的 queryType 中。

movie: {

type: movieType,

args: {

id: { type: GraphQLInt }

},

resolve: function(source, args) {

return _.find(movies, { id: args.id });

}

}

这个请求的返回类型是 movieType,args 参数用于指示 movie 资源路径的输入,这个资源路径的输入是 id,其类型为 GraphQLInt。resolve 函数从电影列表中返回与 id 相匹配的电影。find 是 lodash 中的一个函数,用于查找列表中的元素。

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

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

const _ = require("lodash");

const { movieType } = require("./types.js");

let { movies } = require("./data.js");

//Define the Queryconst 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;

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

添加自定义类型 movieType

创建一个名为 types.js 的文件,并添加以下代码:

const {

GraphQLObjectType,

GraphQLID,

GraphQLString,

GraphQLInt

} = require("graphql");

// Define Movie TypemovieType = new GraphQLObjectType({

name: "Movie",

fields: {

id: { type: GraphQLID },

name: { type: GraphQLString },

year: { type: GraphQLInt },

directorId: { type: GraphQLID }

}

});

exports.movieType = movieType;

可以看出 movieType 是以 GraphQLObjectType 创建的,它有 4 个字段:id,name,year 和 directorId,在添加这些字段时,也会指定每个字段的类型。这些字段直接从数据中来的,在我们的这个例子中,它将来自电影列表。

为 director 资源路径添加查询和类型

和 movie 一样,我们甚至还可以添加 director 资源路径。在 query.js 中,可以按如下方式添加 director 资源路径:

director: {

type: directorType,

args: {

id: { type: GraphQLInt }

},

resolve: function (source, args) {

return _.find(directors, { id: args.id });

}

}

可以在 types.js 中添加 directorType 代码:

//Define Director TypedirectorType = 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 });

}

}

}

});

等等,directorType 与 movieType 略有不同?这是为什么呢?为什么在 directorType 中有 resolve 函数?以前我们看到 resolve 函数只出现在查询中...

directorType 的特殊性

当 director 资源路径被调用时,我们必须返回导演的详细信息,以及该导演指导的所有电影。directorType 中的前 3 个字段 id,name,age 直接从导演列表中获取数据,第 4 个字段 movies 需要包含这位导演的电影列表。为此,我们提到的 movies 字段的类型是 GraphQLList 中的 movieType。

但是我们究竟如何找到这位导演导演的所有电影呢?

为此,我们在 movies 字段里面定义了一个 resolve 函数,resolve 函数的输入参数是 source 和 args,source 将具有父对象的详细信息。

这时候我们让 director 的 id =1, name = "Random" ,age = 20,并且 source.id = 1,source.name ="Random",source.age = 20。

因此,在这个例子中,resolve 函数找出了 directorId 与所需 director 的 id 匹配的所有影片。

代码

GitHub repo 提供了这个项目的完整代码。

应用程序测试

现在让我们测试不同场景的应用程序,使用 node server.js 运行这个程序,本地访问 localhost:5000/graphql 并尝试输入以下内容。

movie

输入:

{

movie(id: 1) {

name

}

}

输出:

{

"data": {

"movie": {

"name": "Movie 1"

}

}

}

输出:

{

"data": {

"director": {

"name": "Director 1",

"id": "1",

"age": 20

}

}

}

从上面我们可以看到客户端可以准确地请求它想要的数据,GraphQL 将确保只返回那些想要的参数。这里仅请求 name 字段,并且仅由服务器返回。

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

输入:

{

movie(id: 3) {

name

id

year

}

}

输出:

{

"data": {

"movie": {

"name": "Movie 3",

"id": "3",

"year": 2016

}

}

}

上面的例子中,请求的字段是:name,id 和 year,所以服务器返回所有这些字段。

director

输入:

{

director(id: 1) {

name

id,

age

}

}

输出:

{

"data": {

"director": {

"name": "Director 1",

"id": "1",

"age": 20

}

}

}

输入:

{

director(id: 1) {

name

id,

age,

movies{

name,

year

}

}

}

输出:

{

"data": {

"director": {

"name": "Director 1",

"id": "1",

"age": 20,

"movies": [

{

"name": "Movie 1",

"year": 2018

},

{

"name": "Movie 2",

"year": 2017

}

]

}

}

}

通过上面的例子,我们看到了 GraphQL 的强大功能。我们想要查找一个 id 为 1 的导演,另外,我们想要找出这位 id 为 1 的导演的所有电影。 director 和 movie 字段都是可定制的,客户可以准确地定制他们想要的字段。

同样,我们还可以扩展到其他字段和类型。例如,我们可以运行一个查询查找 id 为 1 的导演,并根据这位导演找到他所有的电影,再为每部电影找到相对应的演员,并且找出每个获得评级前 5 名的演员所参演的电影,依此类推。对于此查询,我们需要指定类型之间的关系,一旦我们这样做,客户端就可以查询它想要的任何关系。

恭喜

你现在已经了解了 GraphQL 的基本概念。你可以通过查看官方文档来了解有关 GraphQL 的更多信息。

关于原作者

请关注我们的公众号:FENews

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值