GraphQL先后端落地入门尝试总结

前言:首先要明白的是GraphQL是用来干吗的也就是是解决什么问题的,其实就是解决传输数据的可定制化,减小后端api的开发量。举个例子:好比你获取一个用户列表,后端开发了一个叫getUserList接口,参数是parentId,返回的数据结构是这样的:[ { name, id , logo , address } ],后来又有个业务只要数据结构是这样的就能够了:[ { name} ],这个时候要么后端从新开发一个接口,要么就是直接用getUserList,可是形成了数据浪费和网络传输成本浪费,为了解决这个问题GraphQL就被Facebook创造了出来,即能复用getUserList也不形成各类浪费。node

后端(使用的是nodejs,express)

一、安装依赖:npm install express-graphql -S ; npm install graphql -S ; 二、单独个目录作route接口,index.js统一导出,方便之后代码膨胀进行分块,如图
三、开始写具体的业务代码,拿个人base-graphql.js举例ios

// 也能够在不使用 GraphQL Schema Language 的状况下实现相同的 API:
const {
	graphqlHTTP
} = require('express-graphql');
const graphql = require('graphql');
const {
	createBaseDb,
	createUserDb
} = require('../utils/db-util');

//建立db对象
const DBBase = createBaseDb();
// 定义 数据库对应的User类型
const UserType = new graphql.GraphQLObjectType({
	name: 'User',
	fields: {
		id: {
			type: graphql.GraphQLInt
		},
		version: {
			type: graphql.GraphQLInt
		},
		create_date: {
			type: graphql.GraphQLString
		},
		update_date: {
			type: graphql.GraphQLString
		},
		update_user: {
			type: graphql.GraphQLInt
		},
		name: {
			type: graphql.GraphQLString
		},
		email: {
			type: graphql.GraphQLString
		},
		server: {
			type: graphql.GraphQLString
		},
		username: {
			type: graphql.GraphQLString
		},
		password: {
			type: graphql.GraphQLString
		},
	}
});

const UsersType = new graphql.GraphQLList(UserType);

// 定义查询对象类型,对应post查询传参: query:{user(id:"a"){id,name,age},hello(name:"charming")}
const QueryType = new graphql.GraphQLObjectType({
	name: 'Query',
	fields: {
		queryUser: {
			description: 'query user',
			//resolve返回的数据类型
			type: UserType,
			// `args` 描述了 `user` 查询接受的参数
			args: {
				id: {
					type: graphql.GraphQLString,
				}
			},
			resolve(parentValue, args, request) {
				//查一个表的全部数据
				let data = new Promise((resolve, reject) => {
					DBBase.all("select * from user", (err, res) => {
						if (err) {
							reject(err)
						} else {
							resolve(res[0])
						}
					})
				});
				return data;
			}
		},
		queryUsers: {
			description: 'query users',
			//resolve返回的数据类型
			type: UsersType,
			// `args` 描述了 `user` 查询接受的参数
			args: {
				id: {
					type: graphql.GraphQLString,
				}
			},
			resolve(parentValue, args, request) {
				//查一个表的全部数据
				let data = new Promise((resolve, reject) => {
					DBBase.all("select * from user", (err, res) => {
						if (err) {
							reject(err)
						} else {
							resolve(res)
						}
					})
				});
				return data;
			}
		},
		//能够定义多个
		hello: {
			description: 'a hello world demo',
			type: graphql.GraphQLString,
			args: {
				name: { // 这里定义参数,包括参数类型和默认值
					type: graphql.GraphQLString,
					defaultValue: 'Brian'
				}
			},
			resolve(parentValue, args, request) { // 这里演示如何获取参数,以及处理
				return 'hello world ' + args.name + '!';
			}
		}
	}
});

// ====================================下面时修改数据=================================
// 输入参数类型
const UserInputType = new graphql.GraphQLInputObjectType({
	name: 'UserInput',
	fields: () => ({
		name: {
			type: graphql.GraphQLString
		},
		email: {
			type: graphql.GraphQLString
		},
		username: {
			type: graphql.GraphQLString
		},
		password: {
			type: graphql.GraphQLString
		},
	})
});

const MutationType = new graphql.GraphQLObjectType({
	name: 'Mutation',
	fields: {
		addUser: { //参数样式 mutation {addUser(one:{id:"s",name:"alice",age:12,male:false}){id,name,age}}
			type: graphql.GraphQLString,
			// `args` 描述了 `user` 查询接受的参数
			args: {
				one: {
					type: UserInputType
				}
			},
			resolve(parentValue, args, request) {
				let sqlStr = `insert into user (create_date,version,name,email,username,password) values (
					'${new Date().toISOString()}',
					0,
					'${args.one.name}',
					'${args.one.email}',
					'${args.one.username}',
					'${args.one.password}'
				)`;
				return new Promise((resolve, reject) => {
					DBBase.run('BEGIN TRANSACTION;');
					DBBase.run(sqlStr, async (err, res) => {
						console.log("insert user ", err, res);
						if (err) {
							DBBase.run("ROLLBACK;");
							reject(err)
						} else {
							//添加成功后,建立对应的用户数据库
							try {
								await createUserDb(args.one.email);
								DBBase.run('COMMIT TRANSACTION;');
								resolve(res)
							} catch (error) {
								console.log(error);
								DBBase.run("ROLLBACK;");
								reject(err)
							}
						}
					});
				});
			}
		},
	}
});

const schema = new graphql.GraphQLSchema({
	query: QueryType,
	mutation: MutationType
});

module.exports = graphqlHTTP({
	schema: schema,
	graphiql: true /* true表明须要调试 */
})

上面注释写的也比较清楚,简单说下, 这里它提供了GraphQLObjectType来定义对象数据类型的描述,若是是数组必须使用GraphQLList再进行构建,而后你就能够用你构建的来声明你要返回的类型,可是参数类型不能使用这个,必须是GraphQLInputObjectType这种input相关的来构建。 还有resolve方法里是须要你直接return结果的,db的操做其实都是异步的,因此须要你用promise来解决 这个问题,当你的业务涉及事务等比较多db操做是async/await可能更方便,其余的用法就看官方文档吧,这里就不展开了。sql

例子中 我按功能来划分了模块,我综合思考了,仍是以为这样的普适性和开发难度是最好,对于一些复杂的大型项目确定仍是须要进行调整的。 好了到这里,你就能够直接用postman看看效果了 记得参数那里不要是form-data,必定选的是GraphQL(这个我猜测就是form-data等这种现有的形式来作这个可能有点别扭,因此干脆另外定了一个格式),查询参数相似这样:query {queryUsers(id:"a"){id,name,email}},修改参数相似这样:mutation {addUser(one:{name:"jack",email:"jack@qq.com",username:"jack",password:"123456"})};不用postman也能够用自带的,直接访问https://localhost:3001就能够了 。 写到这里你可能会想到现有的相似axios这种的框架不能用了,对的,必需要换成apollo-client这种支持的。因此若是是成熟项目要替换成GraphQL仍是须要成本的。数据库

相关文章
相关标签/搜索