GraphQL 究竟是什么东西?
它实际上是一种 API 查询语言。
GraphQL 显示了服务器可以提供的不同类型的数据,然后客户端就可以明确选择它们想要哪些内容。
在使用 GraphQL 时,你可以在一个调用中获取多个服务器的资源,而不是像 REST API 那样需要调用多个 API。
理论说得再多也没用,例子才是最直观的。所以,让我们开始使用 GraphQL 吧。
我们将在本文中使用 GraphQL 和 NodeJS。
先决条件
下载和安装 NodeJS:https://nodejs.org/en/
如何在 NodeJS 中使用 GraphQL
GraphQL 可以与多种语言一起使用。在这里,我们将重点介绍如何在 NodeJS 中使用 GraphQL。
创建一个叫作 graphql-with-nodejs 的文件夹。进入这个文件夹,并运行 npm init 来创建 NodeJS 项目。
cd graphql-with-nodejs
npm init
复制代码
安装依赖项
使用以下命令安装 Express。
使用以下命令安装 GraphQL。我们将安装 graphql 和 express-graphql。
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 端点。
这个端点是使用 express 创建的。
现在让我们修改代码,启用 GraphQL。
修改代码,启用 GraphQL
GraphQL 将提供一个叫作/graphql 的端点,负责处理所有的请求。
将下面的代码复制到 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}`);
复制代码
我们在/graphql 端点上建立了一个 GraphQL 服务器,它知道如何处理收到的请求。
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
在这个定义中可以看到,query 已被设置为 queryType。
我们使用以下命令从 query.js 文件导入 queryType。
const {queryType} = require('./query.js');
复制代码
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;
复制代码
有关这个 query 的说明
queryType 是一个 GraphQLObjectType 对象,并指定了名称 Query。
我们在 fields 中指定各种端点,我们在这里添加一个叫作 hello 的端点。
hello 的 type 是 GraphQLString,这意味着这个端点的返回类型为字符串。因为这是 graphql schema,所以字符串类型是 GraphQLString 而不是 String。如果直接使用 String 是不行的。
resolve 函数在调用端点时会被执行。这里的操作是返回字符串“Hello World”。
最后,我们使用 exports.queryType = queryType 导出 queryType。这样我们就可以在 server.js 中导入它。
运行应用程序
使用以下命令运行这个应用程序。
应用程序将运行在 localhost:5000/graphql 上。
你可以通过访问 localhost:5000/graphql 来测试应用程序。
Graphiql Web UI 如下图所示。
左侧是输入,右侧是输出。
给定以下输入:
将给出以下输出:
{
"data": {
"hello": "Hello World"
}
}
复制代码
添加更多端点
我们将创建 2 个新端点:
添加数据
通常,应用程序将从数据库中读取数据。但在本文中,我们只是简单地在代码中硬编码一些数据。
创建一个叫作 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;
复制代码
这个文件包含电影和导演的数据。我们将使用这个文件中的数据作为端点的数据来源。
将 movie 端点添加到 query 中
新端点将被添加到 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 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;
复制代码
从上面的代码可以看出,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;
复制代码
可以看出,movieType 是一个 GraphQLObjectType 对象。
它有 4 个字段 id、name、year 和 directorId。在添加这些字段时同时也指定每个字段的类型。
这些字段直接来自之前定义的数据,也就是电影列表。
为 director 端点添加查询和类型
与 movie 端点类似,我们也可以添加 director 端点。
director: {
type: directorType,
args: {
id: { type: GraphQLInt }
},
resolve: function (source, args) {
return _.find(directors, { id: args.id });
}
}
复制代码
在 types.js 中添加 directorType。
//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 });
}
}
}
});
复制代码
directorType 与 movieType 略有不同,为什么会这样?
为什么 directorType 中会有一个 resolve 函数?之前我们只在 query 中看到过这个函数。
directorType 的不同之处
当 director 端点被调用时,我们必须返回导演以及导演所指导的所有电影的信息。
directorType 中的前 3 个字段 id、name、age 直接来自之前定义的数据(导演列表)。
第四个字段 movies 需要包含这位导演所指导的电影列表。
为此,movies 字段的类型是 GraphQLList。
但究竟如何才能找到这位导演指导的所有电影?
为此,我们在 movies 字段中指定了 resolve 函数。这个函数的输入是 source 和 args。
source 将持有父对象的详细信息。
假设某个导演的字段 id = 1、name = “Random”、age = 20,那么source.id = 1
source.name = “Random”、source.age = 20。
因此,在这个示例中,resolve 函数将找出 directorId 与给定导演 ID 相匹配的所有影片。
代码
这个应用程序的完整代码可以在 GitHub(https://github.com/aditya-sridhar/graphql-with-nodejs)上找到。
测试应用程序
现在让我们根据不同的场景来测试这个应用程序。
使用 node server.js 运行应用程序.
访问 localhost:5000/graphql,尝试以下输入。
movie
输入:
输出:
{
"data": {
"movie": {
"name": "Movie 1"
}
}
}
复制代码
从上面可以看出,客户端可以明确地请求它想要的东西,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
}
]
}
}
}
复制代码
英文原文:https://dev.to/adityasridhar/what-is-graphql-and-how-to-use-it-1f58
评论 3 条评论