GraphQL的基础基础
首先
因为对GraphQL有了一些经验,所以我想在接下来的几次中将其总结成文章。
GraphQL是一种用于WEB API的查询语言,用于执行针对现有数据的查询(数据获取命令)的运行时(运行时所需的东西)。
与REST API不同,GraphQL仅有一个端点,并且不需要为每个处理增加额外的端点,因此易于管理,这是它的重要特点之一。
在本文中,我们将参考GraphQL官方教程,实际上编写模式语言,并在GraphQL IDE中编写查询来获取数据。在本文中使用的语言是JavaScript。
GraphQL的历史
GraphQL是由Facebook公司于2012年左右开始开发的,2015年它开源,2018年成立了GraphQL基金会。
截至2020年秋季,不仅Facebook,GitHub、Pinterest和Cousere等公司也都采用了GraphQL。
GraphQL的结构
GraphQL由两个主要组成部分组成,即“查询语言(前端,请求)”和“模式语言(服务器,响应)”。
何谓查询语言?
与GraphQL服务器交互的请求语言(总共3种)。
什么是模式语言?
· 用于描述GraphQL API规范的语言(本文主要在编辑器中撰写此语言)
· 根据以模式语言编写的模式来执行请求查询,由GraphQL处理系统生成响应。
在GraphQL API的定义中,Schema语言仅用于定义规范,不实际进行数据操作。
实际的数据操作由Resolver来完成,即返回特定字段数据的函数(方法)。
GraphQL架构示例
在使用GraphQL的架构中,以下页面提供了一个例子供参考。
通常情况下,GraphQL服务器位于客户端和服务器之间,负责整理和传递数据。
做好准备
在创建项目之后,通过 npm 来安装 GraphQL.js。
mkdir GraphQLPrac
cd GraphQLPrac
touch server.js
npm init
npm install express express-graphql graphql --save
运行GraphQL API服务器
在安装了GraphQL和Node.js框架Express的工作目录中开始工作。
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
// GraphQLスキーマ言語を記述してスキーマを構築する
// スキーマはあくまで定義のみで実際のデータ操作は行わない
const schema = buildSchema(`
type Query {
hello: String
}
`);
// ルートは、APIエンドポイントごとにリゾルバ関数を提供します
// リゾルバとは特定のフィールドのデータを返す関数(メソッド)であり、実際のデータ操作を行う部分
const root = {
hello: () => {
return 'Hello world!';
},
};
// Expressでサーバーを立てます
// graphiql: true としたので、GraphQLを利用できる
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at http://localhost:4000/graphql');
从终端启动服务器。
node server.js
Running a GraphQL API server at http://localhost:4000/graphql
在GraphQL中,可以通过以下方式实现:
1. 在模式定义中定义客户端可以操作的查询和各种类型。
2. 在解析器中执行返回数据的操作。
3. 通过编写查询来实现类似于REST API中的CRUD操作。在本例中,我们获取了定义为hello的模式信息。
基本类型
在GraphQL的模式语言中,存在以下5种标量类型。标量类型是编程语言中的一种数据类型,该类型的数据可以按照大小进行比较和排序。
以下是对这些类型的汉语翻译:
・String(字符串型)
・Int(整型)
・Float(浮点型)
・Boolean(布尔型)
・ID(标识符型)
此外,每种类型还可以被定义为一个列表(有序的数据容器),类型用方括号括起来,如[String]或[Int]这样定义。
const express = require('express');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
// GraphQLスキーマ言語を記述してスキーマを構築する
const schema = buildSchema(`
type Query {
quoteOfTheDay: String
random: Float!
rollThreeDice: [Int]
}
`);
//リゾルバ関数
const root = {
//quoteOfTheDay: String をスキーマで定義
quoteOfTheDay: () => {
return Math.random() < 0.5 ? "Take it easy" : "Salvation lies within";
},
//random: Float! をスキーマで定義
random: () => {
return Math.random();
},
//rollThreeDice: [Int] をスキーマで定義
rollThreeDice: () => {
return [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6));
},
};
const app = express();
app.use(
"/graphql",
graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
})
);
app.listen(4000);
console.log("Running a GraphQL API server at localhost:4000/graphql");
node server.js
Running a GraphQL API server at http://localhost:4000/graphql
我想您已经确认了对返回各种类型API的调用。
参数传递
在GraphQL中,与REST API类似,将参数传递给GraphQL API的端点是常见的做法。通过在模式语言中定义参数,可以自动进行类型检查。
type Query {
rollThreeDice: [Int]
}
在以下示例中,我们将构建一个实际传递参数的模式。
const express = require('express');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
// GraphQLスキーマ言語を記述してスキーマを構築する
// スキーマに引数を指定している
const schema = buildSchema(`
type Query {
rollDice(numDice: Int!, numSides: Int): [Int]
}
`);
//リゾルバ関数
const root = {
//クライアント側のクエリから引数の値を受け取る
rollDice: ({numDice, numSides}) => {
let output = [];
for (var i = 0; i < numDice; i++) {
output.push(1 + Math.floor(Math.random() * (numSides || 6)));
}
return output;
}
};
const app = express();
app.use(
"/graphql",
graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
})
);
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');
node server.js
Running a GraphQL API server at http://localhost:4000/graphql
我已经确认通过在查询中传递参数,返回了按照模式和解析器所定义的结果。
对象类型
如果一个集合中包含了一个或多个由模式定义的字段,那么我们可以称之为对象类型,并且可以像JSON一样进行嵌套。
//type RandomDieの定義を「getDie」で利用
const schema = buildSchema(`
type RandomDie {
numSides: Int!
rollOnce: Int!
roll(numRolls: Int!): [Int]
}
type Query {
getDie(numSides: Int): RandomDie
}
`);
包括解析器在内的代码。
const express = require('express');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
// GraphQLスキーマ言語を記述してスキーマを構築する
const schema = buildSchema(`
type RandomDie {
numSides: Int!
rollOnce: Int!
roll(numRolls: Int!): [Int]
}
type Query {
getDie(numSides: Int): RandomDie
}
`);
//リゾルバ関数内の処理をクラス化することも可能です
class RandomDie {
constructor(numSides) {
this.numSides = numSides;
}
rollOnce() {
return 1 + Math.floor(Math.random() * this.numSides);
}
roll({numRolls}) {
let output = [];
for (var i = 0; i < numRolls; i++) {
output.push(this.rollOnce());
}
return output;
}
}
//リゾルバ関数
const root = {
getDie: ({numSides}) => {
return new RandomDie(numSides || 6);
}
}
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
node server.js
Running a GraphQL API server at http://localhost:4000/graphql
使用对象类型可以知道返回结果是像JSON一样的结构。
突变和输入类型
在创建、更新和删除数据时,使用不同的路由类型(Mutations)而不是查询(Query)。
对于用作Mutation的模式参数,通常使用input关键字而不是type关键字,这样可以轻松地传递对象类型。
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Query {
getMessage(id: ID!): Message
}
// データの追加と更新をスキーマ定義
// 引数にはinputキーワードで定義したMessageInputを使用
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
包括解析器在内的代码。
var express = require('express');
const express = require('express');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
// GraphQLスキーマ言語を記述してスキーマを構築する
const schema = buildSchema(`
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Query {
getMessage(id: ID!): Message
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
`);
class Message {
constructor(id, {content, author}) {
this.id = id;
this.content = content;
this.author = author;
}
}
// データの入れ物
let fakeDatabase = {};
const root = {
getMessage: ({id}) => {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
},
createMessage: ({input}) => {
// ランダムなIdを生成
var id = require('crypto').randomBytes(10).toString('hex');
fakeDatabase[id] = input;
return new Message(id, input);
},
updateMessage: ({id, input}) => {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// 古いデータの書き換え
fakeDatabase[id] = input;
return new Message(id, input);
},
};
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000, () => {
console.log('Running a GraphQL API server at localhost:4000/graphql');
});
node server.js
Running a GraphQL API server at http://localhost:4000/graphql
创建一条新消息
更新消息的内容 de
通过使用突变,我们能够确认消息数据的创建和更新!
最后
我覺得我已經可以網羅地採取上述關於GraphQL基本部分的內容了。
一開始我對於查詢語言和模式語言的差異、寫法以及它們各自的角色並沒有整理清楚,感到有些困惑,但通過反覆閱讀官方文件並動手實踐,我對這一概念有了更深刻的理解。
在下面的文章中,我写了关于GraphQL的Subscription!?
如果您想知道如何实际使用它,请参考本文,在使用Vue作为前端的基础上,总结了在实际应用程序中使用GraphQL的方法,如果方便的话,请参考一下!!
向希望从零开始全面了解GraphQL的人提供指南
我在11月底将一本名为《从基础开始的GraphQL技术书》的书籍在线出版了。这本书的内容是从头学习GraphQL的基本语法和概念,并致力于完成一个使用GraphQL的应用程序。如果您是亚马逊Kindle Unlimited的会员,您可以免费阅读,如果方便的话,可以参考一下!?
那么,再见?