我想在RDB中使用GraphQL
首先
就像标题所说的那样,我想在关系型数据库(MySQL)中使用GraphQL,尽管我平时并不使用它,但我还是尝试用Node编写了一下。
!!但需要只读的中文选项!!
因为直接调用ORM的方法进行写入更方便。
环境
-
- MySQL 5.7
-
- Node 10.11
- NPM 6.4
这是可在GitHub上访问到的成果物链接:https://github.com/lightstaff/graphql-with-sequelize
准备
我们可以使用适当的npm init等命令创建项目,并安装所需的库。
$: npm install --save apollo-server dataloader-sequelize graphql mysql2 sequelize
-
- apollo-server…GraphQLサーバーを簡単に立ち上げてくれる。
-
- graphql…主役
-
- sequelize…ORMライブラリ
-
- dataloader-sequelize…N+1を解決してくれるらしい
- mysql2…MySQLドライバ
关系数据库(RDB)的一侧
我们在ORM中使用Sequelize,但由于我刚开始使用,并不会详细解释。请查看Sequelize的官方文档或官方示例以获取更多详细信息。
创建一个名为models的目录,然后在其中创建User和EMail两个模型。
用户○–< 邮件之间的关系。
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
'user',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING,
},
{
timestamps: false,
tableName: 'user',
}
);
User.associate = models => {
User.hasMany(models.email);
};
return User;
};
module.exports = (sequelize, DataTypes) => {
const EMail = sequelize.define(
'email',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
address: DataTypes.STRING,
},
{
timestamps: false,
tableName: 'email',
}
);
EMail.associate = models => {
EMail.belongsTo(models.user);
};
return EMail;
};
为了能够访问这些内容,我们也需要定义数据库。
const Sequelize = require('sequelize');
const sequelize = new Sequelize('test', 'root', '1234', {
dialect: 'mysql',
host: 'localhost',
port: 3306,
});
module.exports = sequelize;
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const sequelize = require('../database');
const db = {
sequelize,
Sequelize,
};
fs.readdirSync(__dirname)
.filter(file => path.extname(file) === '.js' && file !== 'index.js')
.forEach(file => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
module.exports = db;
GraphQL的一侧
终于谈到正题了。
使用ApolloServer似乎可以轻松构建。
由于非常简单,所以我先提供源代码。
const apolloServer = require('apollo-server');
const dataLoaderSequelize = require('dataloader-sequelize');
const db = require('./models');
const { ApolloServer, gql } = apolloServer;
const { createContext, EXPECTED_OPTIONS_KEY } = dataLoaderSequelize;
// GraphQL schema
const typeDefs = gql`
type User {
id: ID!
name: String
emails: [Email!]!
}
type Email {
id: ID!
address: String
user: User!
}
type Query {
users: [User!]!
user(id: ID!): User
}
`;
// GraphQL <-> ORM
const resolvers = {
User: {
emails: (parent, args, context, info) => parent.getEmails(),
},
Email: {
user: (parent, args, context, info) => parent.getUser(),
},
Query: {
users: (parent, args, { db, eok }, info) =>
db.user.findAll({ [EXPECTED_OPTIONS_KEY]: eok }),
user: (parent, { id }, { db, eok }, info) =>
db.user.findById(id, { [EXPECTED_OPTIONS_KEY]: eok }),
},
};
// Apollo server
const server = new ApolloServer({
typeDefs,
resolvers,
context: {
db: db,
eok: createContext(db.sequelize),
},
});
// Entry point
async function start() {
await db.sequelize.sync({ force: true });
// Setup dummy
const userA = await db.user.create({ name: 'A' });
const userB = await db.user.create({ name: 'B' });
await userA.createEmail({ address: 'A1@e-mail.com' });
await userA.createEmail({ address: 'A2@e-mail.com' });
await userB.createEmail({ address: 'B1@e-mail.com' });
server.listen().then(({ url }) => {
console.log(`? Server ready at ${url}`);
});
}
start();
这个非常简单,不需要解释的……
使用const typeDefs = …来定义GraphQL的模式。
const resolvers = …为GraphQl模式调用数据库并定义解析器。
在这段代码中,使用…创建了ApolloServer,并将数据库等数据提供给了context。
异步函数 start() 是入口点。在启动服务器之前,它会初始化数据库并添加数据。
执行
$ node server.js
进行操作。
如果没有问题的话,Graphql应该可以按照上述方式构建。
最后
我认为这件事做得相当简单,这真是太好了。