【服务器端教程】我们来使用GraphQL吧

你好!这次我想使用GraphQL来创建Todo清单。

※本文将对服务器端进行说明。
点击此处查看有关客户端的文章。

目录

1.这次要制作的东西
2.使用的技术
3.所需的安装
4.本次出现的主要文件
5.马上开始写吧
– 编写app.js
– 编写schema.js
– 连接MongoDB
– 编写models文件夹内的文件
6.方法的写法
7.获取数据
8.添加、编辑、删除数据
– 添加数据
– 编辑数据
– 删除数据
9.尝试测试是否正常运行
10.总结

超大致讲解GraphQL:
– 可以用来从数据库获取信息。
– 只需要一个API的URL(端点)!
– 客户端可以选择自己想要从数据库获取的数据!
→ 不需要在服务器端为每个用途创建一个个的API。可以最低限度地完成。

我们立即开始吧。

1. 这次要做的东西

我将创建一个待办事项应用程序,让每个待办事项都可以带有一个分类,以便能够进行分类。

2. 技术应用

・窗户(10)
・语言:JavaScript
・数据库:MongoDB
・Node.js
・Express
・GraphQL(在Node中使用的图像)

3. 安装必需品.

需要的话,请按照以下的安装步骤进行操作:
1. 创建一个空文件夹,并在其中使用命令提示符进行移动。
2. 运行命令npm install进行安装。

//packagejsonの作成(全部エンターでOK)
npm init

//expressのインストール
npm install express

//変更したらnode.jsを自動で再起動させるため
npm install nodemon

//express-graphqlのインストール
npm install express-graphql

//graphqlのインストール
npm install graphql

//クライアントでデータを取得した際にCorsエラーを阻止する
npm install cors

//MongoDBと接続のため繋ぐためにmongooseのインストール
npm install mongoose

如果您没有安装Node.js,请额外安装。

4. 此次主要亮相的文件

ファイル名説明app.jsサーバに繋ぐ設定用ファイルschema > schema.jsGraphQLの設定用ファイルmodels > todo.js型を設定するファイル(Todo用)models > category.js型を設定するファイル(カテゴリ用).envMongoDBへのアクセスURL

整个形象

image.png

5. 我們立即開始寫吧

写app.js

这里将写下连接到服务器的设置。

//インポートのコーナー===================================================
//exporess
const express = require("express");
const app = express();

//Corsエラー対策用
const cors = require("cors");
app.use(cors());

//サーバの設定============================================================
//ポート番号,起動した際に発動するメソッド
app.listen(4000, () => {
  console.log("express起動したよ");
});

我将尝试通过nodemon启动node.js(express)来执行这个状态。

//appはファイル名
nodemon app
image.png

撰写schema.js

//インポートのコーナー===================================================
//GraphQL
const graphql = require("graphql");
//GraphQL独自の型のインポート(後で追加あり)
const { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLBoolean,
GraphQLList, GraphQLSchema } = graphql;

我们要设置在GraphQL中使用的类型。

/**
 * Todo型.
 */
const TodoType = new GraphQLObjectType({
//型の名前
  name: "Todo",
  fields: () => ({
//使用する変数とその型(ここで使用する型名は上でインポートする必要あり)
    id: { type: GraphQLID },
    title: { type: GraphQLString },
    //Todoが完了したかどうか
    finish: { type: GraphQLBoolean },
    //※下記で説明
    category: {
      //下で設定するカテゴリタイプ
      type: CategoryType,
      resolve(parent, args) {
        return Category.findById(parent.categoryId);
      },
    },
  }),
});
image.png
/**
 * Category型.
 */
const CategoryType = new GraphQLObjectType({
//型の名前
  name: "Category",
//使う変数とその型
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
   //下記で説明
    todoList: {
      //上で設定したTodoタイプのリスト
      type: new GraphQLList(TodoType),
      resolve(parent, args) {
        return Todo.find({ categoryId: parent.id });
      },
    },
  }),
});

虽然与Todo的嵌套原理相同,但是每个分类可能与多个Todo关联,因此需要创建一个名为”Todo列表”的GraphQLList来表示。
例如,分类”阅读”中可能包含有”书籍1″、”书籍2″和”书籍3″等多个Todo。

■连接到MongoDB

//URLのPWとDB名を自分で設定した内容に書き換える必要アリ
DB_URL = MongoDBで発行したURLを記載

让我们在.gitignore中写下设置,以便不要把.env上传到GitHub上。

我們將在 app.js 中添加連接 MongoDB 的配置設定。

//インポートゾーンに追加
//MongoDBに接続のためにmongooseインポート
const mongoose = require("mongoose");
//.envを使用するためにインポート
require("dotenv").config({ debug: true });

/**
 * mongoDBに接続.
 */
mongoose.connect(process.env.DB_URL);

/**
 * mongoDBに接続したら際に発動するメソッド.
 */
mongoose.connection.once("open", () => {
  console.log("mongoDB接続完了");
});

如果在命令提示符(终端)上输入“nodemon app”,并显示“MongoDB连接已成功”则表示正常。

※当MongoDB连接不正常的可能性:
(1)在.env文件中未填入URL、密码和数据库名称。
(2)为了在URL中添加数据库名称,需要先创建数据库,但可能未进行此操作。
(3)IP地址设置不正确。
我尤其在第三种情况下遇到了许多困难。每次WiFi更换时,似乎需要将IP地址添加到“ADD CURRENT IP ADDRESS”中。

在models文件夹内写文件

在这里我们将编写类型设置。
刚才在schema.js中我们已经设置了GraphQL的类型对吧!但是在将信息发送到GraphQL时,我们需要将数据与类型对应起来以进行整理,这也是为了设置的意义之一。

//DBを使う設定
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

/**
 * Todoモデルの作成.
 */
const todoSchema = new Schema({
  title: String,
  finish: Boolean,
//カテゴリIDだけ持たせればカテゴリ情報取得可能なのでIDのみ持たせる
  categoryId: String,
});

//ここで設定した「todoSchema」を「Todo」という名前で使うよ!という宣言
module.exports = mongoose.model("Todo", todoSchema);

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

/**
 * Categoryモデルの作成.
 */
const categorySchema = new Schema({
  name: String,
});

module.exports = mongoose.model("Category", categorySchema);

※在这里设置的变量只需要这样就可以了吗?我知道你可能会这么想。但是在这里我们是为了整理发送的信息而进行类型设置的,所以认为不会用作“添加时”发送信息的就是不必要的。

8. 数据的添加、编辑和删除

6. 连接文件之间

image.png
//インポートゾーンに追加
//モデルのインポート
const Todo = require("../models/todo");
const Category = require("../models/category");
//インポートゾーンに追加
//schema.jsの情報をインポート
const schema = require("./schema/schema");
const graphqlHTTP = require("express-graphql").graphqlHTTP;

/**
 * schemaの使用設定.
 */
app.use(
  "/graphql",
  graphqlHTTP({
    schema,
    graphiql: true,
  })
);

准备工作完成!现在开始编写方法。

这里是当前状态的总结。app.js
const express = require(“express”);
const app = express();
const graphqlHTTP = require(“express-graphql”).graphqlHTTP;
const mongoose = require(“mongoose”);
require(“dotenv”).config({ debug: true });
const schema = require(“./schema/schema”);
const cors = require(“cors”);
app.use(cors());

/**
* 使用schema。
*/
app.use(
“/graphql”,
graphqlHTTP({
schema,
graphiql: true,
})
);

/**
* 端口号,启动时触发的方法。
*/
app.listen(4000, () => {
console.log(“express已启动”);
});

/**
* 连接到MongoDB。
*/
mongoose.connect(process.env.DB_URL);
/**
* 连接到MongoDB时触发的方法。
*/
mongoose.connection.once(“open”, () => {
console.log(“MongoDB连接成功”);
});

schema.js
const graphql = require(“graphql”);
const { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLBoolean, GraphQLList, GraphQLSchema } = graphql;
//模型
const Todo = require(“../models/todo”);
const Category = require(“../models/category”);

/**
* Todo类型。
*/
const TodoType = new GraphQLObjectType({
name: “Todo”,
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString },
finish: { type: GraphQLBoolean },
category: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.categoryId);
},
},
}),
});

/**
* Category类型。
*/
const CategoryType = new GraphQLObjectType({
name: “Category”,
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
todoList: {
type: new GraphQLList(TodoType),
resolve(parent, args) {
return Todo.find({ categoryId: parent.id });
},
},
}),
});

todo.js
const mongoose = require(“mongoose”);
const Schema = mongoose.Schema;

/**
* 创建Todo模型。
*/
const todoSchema = new Schema({
title: String,
finish: Boolean,
categoryId: String,
});

module.exports = mongoose.model(“Todo”, todoSchema);

category.js
const mongoose = require(“mongoose”);
const Schema = mongoose.Schema;

/**
* 创建Category模型。
*/
const categorySchema = new Schema({
name: String,
});

module.exports = mongoose.model(“Category”, categorySchema);

6. 方法的编写方式 de

我想要编写GraphQL的方法,所以我会在schema.js中进行编写。
GraphQL的方法包括:
– 获取数据→Query
– 添加、编辑和删除数据→Mutation
这样写起来很容易记住。

7. 获取数据

首先要准备好查询的框架。

const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
 //ここにメソッドを追加していく
  },
});

//外部から使用できるようにエクスポートしておく
module.exports = new GraphQLSchema({
  query: RootQuery,
});

我们继续在fields的方法部分添加方法。

■获取一条信息

    /**
     * Todo情報取得.
     */
    //メソッド名
    getTodo: {
     //使用するGraphQL型(上で設定したやつを使用)
      type: TodoType,
     //ユーザが入力する検索ワードとその型
      args: { id: { type: GraphQLID } },
     //検索結果どう処理して何を返すか
      resolve(parents, args) {
       //argsに入れたIDと同じものをTodo全件から探す→当てはまったものを返す
        return Todo.findById(args.id);
      },
    },

以相同的方式获取1个类别信息。

    /**
     * category情報取得.
     */
    getCategory: {
      type: CategoryType,
      args: { id: { type: GraphQLID } },
      resolve(parents, args) {
        return Category.findById(args.id);
      },
    },

获取所有的Todo信息

如果全件退还的情况下,不需要进行特殊处理,所以这里相对比较简单。

  /**
     * 全Todo情報の取得.
     */
    getAllTodo: {
     //返ってくるデータは複数あるので、リストになる
      type: new GraphQLList(TodoType),
      resolve(parent, args) {
        return Todo.find({});
      },
    },

准备方法时,也要按照相同的类别进行。

    /**
     * 全Category情報の取得.
     */
    getAllCategory: {
      type: new GraphQLList(CategoryType),
      resolve(parent, args) {
        return Category.find({});
      },
    },

8. 数据的添加、编辑和删除

首先要准备变异框架。


const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
//ここにメソッドを追加していく
  },
});

//外部から使用できるようにエクスポートしておく(取得の際に書いた部分に追記)
module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation,
});

现在让我们像在获取时一样,在这里添加方法…

■添加数据

 /**
     * Todoの追加
     */
   //メソッド名
    addTodo: {
     //使用するGraphQL型
      type: TodoType,
     //ユーザが入力の必要がある情報(今回追加のため、追加内容全て)
      args: {
        title: { type: GraphQLString },
        //カテゴリと紐づけるために必要
        categoryId: { type: GraphQLID },
        finish: { type: GraphQLBoolean },
      },
      resolve(parent, args) {
       //Todoモデルの型に沿って、情報を作成する
        let todo = new Todo({
          title: args.title,
          categoryId: args.categoryId,
          finish: false,
        });
        //上で作成したデータtodoをDBに保存する
        return todo.save();
      },
    },
    /**
     * categoryの追加.
     */
    addCategory: {
      type: CategoryType,
      args: {
        name: { type: GraphQLString },
      },
      resolve(parent, args) {
        let category = new Category({
          name: args.name,
        });
        return category.save();
      },
    },

■数据编辑

如果将其写在Mutation内部也可以。

   /**
     * Todoの更新.
     * @remarks 項目名、カテゴリ編集可能
     */
    updateTodo: {
     //使うGraphQL型
      type: TodoType,
     //ユーザが入力する情報
      args: {
        //※注意!
        id: { type: new GraphQLNonNull(GraphQLID) },
        title: { type: GraphQLString },
        categoryId: { type: GraphQLID },
      },
      resolve(parent, args) {
        //一旦空の連想配列を準備
        let updateTodo = {};
        //入力したタイトルがあれば、updateTodoのtitleに入力データを入れる
        args.title && (updateTodo.title = args.title);
        //入力したカテゴリがあれば、updateTodoのcategoryに入力データを入れる
        args.categoryId && (updateTodo.categoryId = args.categoryId);
        //該当のTodoにupdateTodoの情報を上書き
        //findByIdAndUpdateという元々あるメソッドを使用
        return Todo.findByIdAndUpdate(args.id, updateTodo, {
          //更新したデータを返す
          new: true,
        });
      },
    },

请注意!有一个新的类型出现了,请在schema.js文件的顶部导入GraphQL类型的导入语句中添加它!这个新类型叫做”GraphQLNonNull”,用于在需要设置”该字段不能为空”时使用。(在这个例子中,由于没有ID,无法确定要更新哪个待办事项,所以这是必需的。)

const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLBoolean,
  GraphQLSchema,
  GraphQLList,
//追加
  GraphQLNonNull,
} = graphql;

我们将类别的更新方法也同样添加进去。

    /**
     * categoryの更新.
     */
    updateCategory: {
      type: CategoryType,
      args: {
        id: { type: new GraphQLNonNull(GraphQLID) },
        name: { type: GraphQLString },
      },
      resolve(parent, args) {
        let updateCategory = {};
        args.name && (updateCategory.name = args.name);
        return Category.findByIdAndUpdate(args.id, updateCategory, {
          new: true,
        });
      },
    },

此外,我們還要在To-do完成時將finish設為true,因此我們需要新增該方法。

   /**
     * Todoの完了.
     */
    finishTodo: {
      type: TodoType,
      args: {
        id: { type: new GraphQLNonNull(GraphQLID) },
        finish: { type: GraphQLBoolean },
      },
      resolve(parent, args) {
        let finishTodo = {};
        finishTodo.finish = args.finish;
        return Todo.findByIdAndUpdate(args.id, finishTodo, {
          new: true,
        });
      },
    },

■删除数据

只要在Mutation中写下相同的东西,就可以了。
只要输入ID,就知道要删除的数据,所以处理起来并不是很困难。

 /**
     * Todoの削除.
     */
    deleteTodo: {
      type: TodoType,
      args: {
        id: { type: new GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
        //findByIdAndRemoveという元々あるメソッドを使用
        return Todo.findByIdAndRemove(args.id);
      },
    },
   /**
     * categoryの削除.
     */
    deleteCategory: {
      type: CategoryType,
      args: {
        id: { type: new GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
        return Category.findByIdAndRemove(args.id);
      },
    },

试试看是否进行顺利。

image.png
image.png

接下来,在这个页面的左侧,我将按照下面的规则将代码放在一片杂乱的文字区域中(可以删除灰色的文字)。

・取得→queryで囲む/追加、編集、削除→mutationで囲む
・()内→送るデータ(argsで設定したもの)
・{}内→返して欲しいデータ

パターン1:データの全件取得
query{
メソッド名{
 返して欲しいデータ
 }
}

パターン2:データを1件取得(argsに値を入れる必要がある際)
query{
 メソッド名(id:検索IDの値){
  返して欲しいデータ
 }
}
※idがuserIdだったり変数名は自身の設定した名前に変えてください。

パターン3:mutationの場合
mutation{
 メソッド名(送るデータ変数名:送るデータ値){
  返して欲しいデータ
 }
}

在输入后,点击左上方的「▸」,如果成功获取到数据,则表示成功。请尝试逐个尝试每个方法。

//パターン1の入力例
query{
  getAllTodo{
    title
 }
}

//パターン2の入力例
//※このようにネストさせてTodoのタイトルと対応するカテゴリの名前等を取得も可能
query{
  getTodo(id:"DBで確認したTodoのID"){
    title
    category{
     name  
  }
 }
}

//パターン3の入力例
mutation{
  addTodo(title:"新しいTodo",
  categoryId:"カテゴリID",
  finish:false){
    title
  }
}
※应用
(1)同时触发多个方法
将它们排列起来触发即可GraphiQL
query{
getAllTodo{
title
}
getAllCategory{
name
}
}

(2)如果想先将输入数据存储到变量中

GraphiQL
//query($变量名:GraphQL类型){方法名(变量名:$变量名){想要返回的数据}}
//如果是必要的,则在类型后面加上!,否则不需要
query($id:ID!){
getTodo(id:$id){
title
finish
}
}

在左下方的“QUERY VARIABLES”中输入具体的值

GraphiQL(QUERY VARIABLE)
//注意,将变量部分用””括起来!
{“id”:”想要获取的Todo列表的ID”}

在这个状态下,点击“‣”即可获取数据。
了解这些写法在客户端获取数据时非常有用。

当服务器端处理完成时,一切就绪!辛苦了。

总结

请使用GraphQL来总结如何创建方法。由于还有许多不成熟的地方,请如果有任何问题或错误请告知。

我计划将来整理一下关于客户端的内容,并感谢您到目前为止的观看。

这次创建的代码的GitHub。

广告
将在 10 秒后关闭
bannerAds