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种)。

クエリの種類意味効果queryデータ取得系GETmutationデータ更新系POST/PUT/DELETE…etcsubscriptionイベントの通知Websocket

什么是模式语言?

· 用于描述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
スクリーンショット 2020-10-12 20.40.41.png

在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
スクリーンショット 2020-10-12 21.43.17.png

我想您已经确认了对返回各种类型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
スクリーンショット 2020-10-12 22.09.41.png

我已经确认通过在查询中传递参数,返回了按照模式和解析器所定义的结果。

对象类型

如果一个集合中包含了一个或多个由模式定义的字段,那么我们可以称之为对象类型,并且可以像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
スクリーンショット 2020-10-12 23.01.21.png

使用对象类型可以知道返回结果是像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
createMessage.png

创建一条新消息

updateMessage.png

更新消息的内容 de

message-wuery.png

通过使用突变,我们能够确认消息数据的创建和更新!

最后

我覺得我已經可以網羅地採取上述關於GraphQL基本部分的內容了。
一開始我對於查詢語言和模式語言的差異、寫法以及它們各自的角色並沒有整理清楚,感到有些困惑,但通過反覆閱讀官方文件並動手實踐,我對這一概念有了更深刻的理解。

在下面的文章中,我写了关于GraphQL的Subscription!?
如果您想知道如何实际使用它,请参考本文,在使用Vue作为前端的基础上,总结了在实际应用程序中使用GraphQL的方法,如果方便的话,请参考一下!!

向希望从零开始全面了解GraphQL的人提供指南

我在11月底将一本名为《从基础开始的GraphQL技术书》的书籍在线出版了。这本书的内容是从头学习GraphQL的基本语法和概念,并致力于完成一个使用GraphQL的应用程序。如果您是亚马逊Kindle Unlimited的会员,您可以免费阅读,如果方便的话,可以参考一下!?

那么,再见?

广告
将在 10 秒后关闭
bannerAds