使用简单的GraphQL服务器进行CRUD操作(Express.js,Objection.js,MySQL,Docker)
首先
当我开始学习GraphQL时,我感到了一丝难度?。从“如果我再次从头开始学习GraphQL的话,如果有这样一篇文章就好了”这个角度出发,我创建了一个简单的GraphQL应用,代码量很少,但功能正常。
我认为这是一个可以在20分钟内完成的实践,但是如果您很忙的话,您可以仅仅看一下”添加文件 -> 服务器”这部分?
如果在产品中使用GraphQL,我认为有很多需要考虑的事情,比如设计更具可维护性的目录结构,考虑对N+1进行优化等等。但是这次我们不去碰这些。
开发环境和所用的技术
-
- OS: macOS Catalina 10.15.4
-
- サーバー: Express.js
-
- ORM: Objection.js(内部でKnex.jsを利用してる)
-
- DB: MySQL8系
-
- ツール
node: 16.8.0
yarn: 1.22.17
docker: 20.10.7
docker-compose: 1.29.2
目录结构
.
├── graphql
│ └── user.gql
├── migrations
│ └── 20211225000000_users.js
├── models
│ └── User.js
├── seeds
│ └── users.js
├── docker-compose.yml
├── knexfile.js
├── package.json
├── server.js
└── yarn.lock
亲身体验
建立环境
在创建package.json文件之后,执行yarn install安装依赖库。
{
"version": "1.0.0",
"dependencies": {
"express": "^4.17.1",
"express-graphql": "^0.12.0",
"graphql": "^15.7.2",
"knex": "^0.95.14",
"mysql2": "^2.3.3",
"objection": "^3.0.0",
"nodemon": "^2.0.15"
},
"scripts": {
"dev": "nodemon server.js"
}
}
在创建docker-compose.yml文件后,使用docker-compose up命令来启动mysql服务器。
version: '3.8'
services:
my-db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
command: --default-authentication-plugin=mysql_native_password
volumes:
- ./mysql:/var/lib/mysql
使用自己喜欢的方式,在我的 my-db 容器内创建一个名为 dev_db 的数据库。
root@1234567890:/#
root@1234567890:/# mysql -u root -p
输入密码:
〜 输入docker-compose.yml中设置的MYSQL_ROOT_PASSWORD的值 〜
欢迎来到MySQL监视器。输入命令以;或\g结尾。
〜 省略 〜
mysql>
mysql> CREATE DATABASE dev_db;
查询已受影响的行数:1(耗时0.05秒)
mysql> show databases;
+——————–+
| Database |
+——————–+
| dev_db |
| information_schema |
| mysql |
| performance_schema |
| sys |
+——————–+
结果集中的5行(耗时0.01秒)
mysql> exit
再见
root@123456789:/# exit
使用knex创建表格和虚拟数据
添加 knexfile.js 文件,并记录下与数据库的连接信息。
module.exports = {
development: {
client: 'mysql2',
connection: {
database: "dev_db",
user: "root",
password: "password",
}
}
};
运行yarn knex migrate:make users命令会生成migrations/〇〇_users.js文件。
修改生成的迁移文件
exports.up = function(knex) {
return knex.schema.createTable('users', t => {
t.increments('id')
t.string('name')
t.integer('age')
})
};
exports.down = function(knex) {
return knex.schema.dropTable('users')
};
运行以下命令以应用最新的 yarn knex 迁移:
yarn knex migrate:latest
使用yarn knex seed:make users来创建种子文件。
修改生成的种子文件
exports.seed = function(knex) {
// Deletes ALL existing entries
return knex('users').del()
.then(function () {
// Inserts seed entries
return knex('users').insert([
{id: 1, name: 'Catherine', age: 4},
{id: 2, name: 'Mike' , age: 8},
{id: 3, name: 'Gonzales' , age: 16},
{id: 4, name: 'Nancy' , age: 32},
{id: 5, name: 'Daniel' , age: 64},
]);
});
};
使用yarn knex seed:run命令运行seed。
添加文件
-
- サーバー: server.js
参考サイト: express-graphql
const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
const fs = require('fs');
const schema = buildSchema(fs.readFileSync('./graphql/user.gql', 'utf8'));
const User = require('./models/User');
const readUsers = async () => {
const users = await User.query().select();
return users;
};
const createUser = async ({name, age}) => {
const user = await User.query().insert({name: name, age: age});
return user;
};
const updateUser = async ({id, name, age}) => {
await User.query().findById(id).update({name: name, age: age});
return User.query().findById(id);
};
const deleteUser = async ({id}) => {
await User.query().findById(id).delete();
};
const root = {
readUsers: readUsers,
createUser: createUser,
updateUser: updateUser,
deleteUser: deleteUser,
};
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")
);
- GraphQLの定義ファイル: graphql/user.gql
type Query {
readUsers: [User]
},
type Mutation {
createUser(name: String!, age: Int): User
updateUser(id: Int!, name: String, age: Int): User
deleteUser(id: Int!): User
}
type User{
id: Int
name: String
age: Int
}
- Objection.jsのmodelファイル: models/User.js
const { Model } = require('objection');
const knex = require('knex');
const KnexConfig = require('../knexfile');
Model.knex(knex(KnexConfig.development));
class User extends Model {
static get tableName() {
return 'users';
}
}
module.exports = User;
-
- yarn devコマンドで起動
- http://localhost:4000/graphql にアクセス
在GraphiQL网站上试着获取数据。
query readUsers {
readUsers {
id
name
age
}
}
mutation createUser($name: String!, $age: Int) {
createUser(name: $name, age: $age) {
... userFields
}
}
fragment userFields on User {
name
age
}
# 以下はQUERY VARIABLESに入力
{
"name": "Johnny",
"age": 1
}
mutation updateUser($id: Int!, $name: String!, $age: Int) {
updateUser(id: $id, name: $name, age: $age) {
... userFields
}
}
fragment userFields on User {
id
name
age
}
# 以下はQUERY VARIABLESに入力
{
"id": 3,
"name": "Akira",
"age": 2
}
mutation deleteUser($id: Int!) {
deleteUser(id: $id) {
... userFields
}
}
fragment userFields on User {
name
age
}
# 以下はQUERY VARIABLESに入力
{
"id": 5
}
最后
希望这个简单的功能能成为你接触GraphQL的契机。非常感谢你阅读到最后!
如果可以的话,请看看我们公司圣诞节日历的其他文章吧?♂️