GraphQL前後端落地入門嘗試總結

前言:首先要明白的是GraphQL是用來幹嘛的也就是是解決什麼問題的,其實就是解決傳輸數據的可定製化,減少後端api的開發量。舉個例子:比如你獲取一個用戶列表,後端開發了一個叫getUserList接口,參數是parentId,返回的數據結構是這樣的:[ { name, id , logo , address } ],後來又有個業務只要數據結構是這樣的就可以了:[ { name} ],這個時候要麼後端重新開發一個接口,要麼就是直接用getUserList,但是造成了數據浪費和網絡傳輸成本浪費,爲了解決這個問題GraphQL就被Facebook創造了出來,即能複用getUserList也不造成各種浪費。

後端(使用的是nodejs,express)

1、安裝依賴:npm install express-graphql -S ; npm install graphql -S ; 2、單獨個目錄做route接口,index.js統一導出,方便以後代碼膨脹進行分塊,如圖
3、開始寫具體的業務代碼,拿我的base-graphql.js舉例

// 也可以在不使用 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可能更方便,其他的用法就看官方文檔吧,這裏就不展開了。

例子中 我按功能來劃分了模塊,我綜合思考了,還是覺得這樣的普適性和開發難度是最好,對於一些複雜的大型項目肯定還是需要進行調整的。 好了到這裏,你就可以直接用postman看看效果了 記得參數那裏不要是form-data,一定選的是GraphQL(這個我猜想就是form-data等這種現有的形式來做這個可能有點彆扭,所以乾脆另外定了一個格式),查詢參數類似這樣:query {queryUsers(id:"a"){id,name,email}},修改參數類似這樣:mutation {addUser(one:{name:"jack",email:"[email protected]",username:"jack",password:"123456"})};不用postman也可以用自帶的,直接訪問https://localhost:3001就可以了 。 寫到這裏你可能會想到現有的類似axios這種的框架不能用了,對的,必須要換成apollo-client這種支持的。所以如果是成熟項目要替換成GraphQL還是需要成本的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章