【服务器端教程】我们来使用GraphQL吧
你好!这次我想使用GraphQL来创建Todo清单。
※本文将对服务器端进行说明。
点击此处查看有关客户端的文章。
目录
1.这次要制作的东西
2.使用的技术
3.所需的安装
4.本次出现的主要文件
5.马上开始写吧
– 编写app.js
– 编写schema.js
– 连接MongoDB
– 编写models文件夹内的文件
6.方法的写法
7.获取数据
8.添加、编辑、删除数据
– 添加数据
– 编辑数据
– 删除数据
9.尝试测试是否正常运行
10.总结
– 可以用来从数据库获取信息。
– 只需要一个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. 此次主要亮相的文件
整个形象
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
撰写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);
},
},
}),
});
/**
* 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连接已成功”则表示正常。
(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. 连接文件之间
//インポートゾーンに追加
//モデルのインポート
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,
})
);
准备工作完成!现在开始编写方法。
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);
},
},
试试看是否进行顺利。
接下来,在这个页面的左侧,我将按照下面的规则将代码放在一片杂乱的文字区域中(可以删除灰色的文字)。
・取得→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。