1
cyril4free 2018-11-08 09:50:10 +08:00
隔壁组的同事已经用上了,据说很爽。。免去了前后端对接口参数的困扰。。
|
2
fzleee 2018-11-08 09:59:23 +08:00
所以,GQL 是个什么东西...
|
3
gzf6 OP |
4
heww 2018-11-08 10:06:27 +08:00 via iPhone
用起来很爽,不用费什么脑子。但它的 js client 不好用。
|
5
IsaacYoung 2018-11-08 10:39:20 +08:00
去 redux 化
|
6
reus 2018-11-08 10:57:06 +08:00
如果需要高性能,后端就要手写,就没法自动生成代码
如果自动生成代码,那性能…… 就好像查询不需要开销似的 关系数据库本质不是图数据库,后端需要实现这两种模型之间的转换,没有简单高效的办法 反正我是不想做这种东西,除非有图数据库可以替代关系数据库 |
7
trait 2018-11-08 11:08:58 +08:00 via iPhone
应该不错,GitHub 的 gql 版本 api 已经有了,正在过渡,Twitter 貌似也在用
|
8
TommyLemon 2018-11-08 11:15:48 +08:00 3
说明很多公司都前后端分离后碰到了各种恼人的开发与沟通问题
1.浪费性能、流量和带宽 返回不需要的字段、对象等 2.各种奇葩的缩写、混乱的命名 各种缩写、拼音、驼峰和非驼峰混用等, 只有看文档才知道是什么、才知道用哪个,而且文档还很可能有错误。 例如 评论数量可能是 commentCount, comment_count, cmt_count, pl_num... 分页页码可能是 page, pageNum, page_number, page_num, pnum... 3.数据类型不稳定或随意改变 对象为空时应该返回 null 或 {} ,但实际会返回空数组 [], 甚至是 "", "[]" 等 ,导致前端解析崩溃; 后端擅自改变类型导致线上 App 崩溃... 4.几百甚至上千个混乱的状态码 各项目几乎完全不通用,不看相关的内部文档根本不知道对应的错误是什么,而且文档还很可能有错误。 例如 注册: 成功 600, 手机号不合法 601, 验证码错误 603, 手机号已注册 607, 缺少必要字段 609... 评论: 成功 1070, 不允许评论 1071, 参数错误 1073, 动态被删除 1075... 5.文档过时,与接口不同步 后端把接口改了没有及时通知,前端 /客户端莫名其妙调了半天才发现 6.应用界面和接口强耦合难分离 比如某个版本的 QQ 空间动态的 JSON 结构必须对应某个版本的某个接口, 有时候 JSON 结构甚至是由后端拍脑袋决定的,不好用也得用 7.版本迭代导致大量重复功能的接口 为了兼容旧版应用不好直接改原来的接口,一般只能新增 8.前端 /客户端与后端扯皮 前端 /客户端想要一次性返回或者更方便解析的结构,但后端想要少写代码 9.数据库操作不安全 delete 忘加 where 直接删光全部数据,只要发生一次 10.开发流程繁琐周期长 后端写接口>后端写文档>前端 /客户端查文档>(前端 /客户端关于文档向后端提问>后端解决问题并通知或等待再次被问)>前端 /客户端调用接口>(前端 /客户端关于实际使用向后端提问>后端解决问题并通知或等待再次被问)>前端 /客户端解析返回结果>(前端 /客户端关于返回内容或结构向后端提问>后端解决问题并通知或等待再次被问) ... Facebook 出的 GraphQL 部分解决了这些问题,让它们看到了希望 |
9
TommyLemon 2018-11-08 11:18:31 +08:00
@heww @reus @TommyLemon
APIJSON 比 GraphQL 强大易用很多,解决了以上所有问题, 并且不用写 Schema,Type,resolver 等一堆东西, 它会自动将前端传的 JSON 参数转为 SQL 语句执行并返回结果, 期间自动校验权限、结构、内容,自动防 SQL 注入。 还有自动化的各种 JOIN(INNER, LEFT, RIGHT 等)解决 N+1 问题。 还支持多字段排序 order by,多字段分组 group by,聚合函数 having 等几乎所有 MySQL 的常规功能。 juejin.im/post/5ae80edd51882567277433cf 创作不易,GitHub 右上角点 Star 支持下吧,谢谢 ^_^ github.com/TommyLemon/APIJSON |
10
find456789 2018-11-08 11:21:12 +08:00
我是小白
感觉权限是个问题呀, 比如 没有登陆会员只能查看 3 个字段,vip 能查看 5 个字段, 管理员能查看所有字段, 这在 gql 上是不是很难实现呀? |
11
TommyLemon 2018-11-08 11:24:58 +08:00 1
|
12
Hilong 2018-11-08 11:30:39 +08:00 via Android
@TommyLemon 昨天还看到公众号推送去搜索了 下,支持
|
13
asd123456cxz 2018-11-08 11:45:15 +08:00
@TommyLemon #11 看到老哥推广好多次了。。支持下
|
14
TommyLemon 2018-11-08 11:54:52 +08:00
@Hilong @asd123456cxz 感谢。
其实我有时也在一些技术群推广 GraphQL,在公司也为 GraphQL 开过分享会。 不怕对比,就怕大家不知道、不认可 前端定制接口 的做法。 一部分用户是因为先了解到 GraphQL,然后看不懂、不会用、用起来麻烦, 后面看到 APIJSON 就转了过来。 |
15
RubyJack 2018-11-08 11:55:17 +08:00
性能一塌糊涂
|
16
clino 2018-11-08 12:04:16 +08:00
@TommyLemon 能用在 python 后端上吗?
|
17
TommyLemon 2018-11-08 12:09:44 +08:00
@RubyJack GraphQL 是用来自动整合其它接口或服务的,性能取决于 整合方式 以及 原来的接口或服务的性能。
如果就是简单地把几个接口拼在一起返回数据,很容易引发 N+1 次查询 /调用,性能就差了, 所以 Facebook 又搞了个 [DataLoader]( https://github.com/facebook/dataloader), 从主查询(主表)里取出 副查询(副表)需要的所有 id, 将原来 N 次 WHERE id=$id 副查询 变为一次 WHERE id IN( $idList ) 来优化性能, 但使用 DataLoader 要写 userLoader 等一些实例 ```js var DataLoader = require('dataloader') var userLoader = new DataLoader(keys => myBatchGetUsers(keys)); ``` 并且实现初始化 ```js function createLoaders(authToken) { return { users: new DataLoader(ids => genUsers(authToken, ids)), } } ``` 和调用方法 ``` // Request begins... var userLoader = new DataLoader(...) // And a value happens to be loaded (and cached). userLoader.load(4).then(...) // A mutation occurs, invalidating what might be in cache. sqlRun('UPDATE users WHERE id=4 SET username="zuck"').then( () => userLoader.clear(4) ) // Later the value load is loaded again so the mutated data appears. userLoader.load(4).then(...) // Request completes. ``` 在原来写一堆 Schema,Type,Resolver 的基础上又增加了不少工作量。 APIJSON 直接提供自动化的 join,不需要后端写任何代码,前端传一个 join 键值对就行: ```js { "[]": { //查询数组 "join": "</User/id@", // Comment LEFT JOIN User ON User.id = Comment.userId "Comment": {}, "User": { "id@": "/Comment/userId", "@column": "id,name" // SELECT id,name } } } ``` 可以用 APIJSONAuto-自动化接口管理平台 在线测试 http://apijson.org |
18
feverzsj 2018-11-08 12:11:51 +08:00
前端老是喜欢搞些低能的东西
|
19
TommyLemon 2018-11-08 12:12:20 +08:00
@clino
目前只有 Java,C#, PHP, Node.js 的后端实现 以及 Android,iOS,JavaScript 的 Demo。 但 APIJSON 的协议是与语言无关的,可以用 Python 等其它语言实现,可以参考这个引导 github.com/TommyLemon/APIJSON/issues/38 |
20
buhi 2018-11-08 12:16:52 +08:00
大兄弟, 你怎么保证你这个自己一个人在做的东西就能比 fb 一个大厂在 backup 的东西要好用呢
|
21
TommyLemon 2018-11-08 12:40:14 +08:00
@buhi
不是保证,是基于事实的对比。 APIJSON 与 GraphQL 全方位对比解析(一)-基础功能 juejin。im/post/5ae80edd51882567277433cf APIJSON 与 GraphQL 全方位对比解析(二)-权限控制 juejin。im/post/5b17518c6fb9a01e75463096 APIJSON 与 GraphQL 全方位对比解析(三)-表关联查询 juejin。im/entry/5b4ff88f6fb9a04f914a8df5 如果你单纯用影响力来对比,那 OKHTTP,Mybatis,RxJava,Vue.js 等 早期由个人开发者做起来的项目都不能和 FLAG 等大公司同类项目比了,更不可能超过了。 GraphQL 硬生生地把加强版 API Proxy 做成了一门编程语言(#import,$variable...), 基础的问题(定制结构、分组排序、JOIN 等)没都解决好,还越做越复杂,概念满天飞。 那套新的协议还真只有 Facebook 那种水平的大牛才能准确高效地解析出来, 不过毕竟是新协议,怎么都不会比发展了快 20 年的 JSON 更成熟方便。 APIJSON 基于 JSON 扩展而来,不但提供了几乎所有 SQL 常用功能+远程函数等其它功能, 还可以很好地利用 JSON 的生态,可以用一大堆成熟的封装与解析库,一大堆视频博客等教程, 一大堆方便好用的调试工具(Chrome 控制台、Postman 等对 JSON 内置支持)... 而且现在 APIJSON 主项目(Java)也有 4 个开发者在维护,支持 MySQL, PostgreSQL, Oracle。 还有其它 3 个作者分别实现了 APIJSON 的 C#, PHP, Node.js 版。 加上 APIJSONAuto 自动化接口管理工具( GraphiQL,Graphcool 的 PlayGround,Apollo Client Devtools,GraphQLIDE 好用很多,你可以都对比下)已经有一个初具雏形的 APIJSON 生态了。 |
22
TommyLemon 2018-11-08 12:43:44 +08:00
@TommyLemon 是 APIJSONAuto 比它们好用很多,它们只在支持代码自动补全有优势,
而 APIJSONAuto 的 自动注释请求、自动生成代码、自动化回归测试(前后对比测试+机器学习测试)是它们都没有的。 http://apijson。org/ |
23
kran 2018-11-08 12:50:27 +08:00
@TommyLemon apijson 怎么和权限认证配合的?
|
24
reus 2018-11-08 13:11:46 +08:00
@TommyLemon 我们有自己的方案,不用你这破东西
|
25
likuku 2018-11-08 13:17:40 +08:00 2
刚看到阮一峰的推文: [看到一句妙语。“ GraphQL 的本质是程序员想对 JSON 使用 SQL。”]
https://twitter.com/ruanyf/status/1060350454238859264 |
26
zjsxwc 2018-11-08 13:29:11 +08:00 via Android
25 楼说的对,本质就是把 json 转 sql
|
27
Narcissu5 2018-11-08 13:34:25 +08:00
第一反应这不就是当年的 web service 么,无非 xml 换成了 json。不知道为什么 facebook 总喜欢重蹈覆辙,react 也是一样的感觉
|
29
TommyLemon 2018-11-08 14:30:26 +08:00 1
|
30
TommyLemon 2018-11-08 14:32:10 +08:00
@reus 还请您把方案拿出来和“我这破东西”对比下,让大家也长长见识,顺便给与支持
|
31
vipppppp 2018-11-08 14:34:51 +08:00
之前还没了解过,刚刚看了一下 GQL,下了个 python 的 demo 看了一下,感觉确实就是 json 转 sql
至于 apijson 只能说我无福享受啊,毕竟我是个 python 程序员 = = |
32
TommyLemon 2018-11-08 14:47:04 +08:00 1
@vipppppp 唉,之前有个开发者在 issue 里留言说在做 Python 版:
“刚刚把单元测试写好。json 的表现层完全自定义,都是为了对应 sql ” 到现在有 2 个月了也没更新 github。com/TommyLemon/APIJSON/issues/38 |
34
buhi 2018-11-08 15:27:15 +08:00
@Narcissu5 我觉得 react 只是说很容易写出逻辑和展示高度耦合的代码而已, 并不是 react 自己有在鼓励这种写法.
|
35
whypool 2018-11-08 16:09:08 +08:00
fb 出的东西,真的不敢恭维,也就剩下 fb 这大厂在背书了
如果这是其他公司出的,估计会被喷成翔,即使红透了的 react 也一样 |
36
sologgfun 2018-11-08 16:47:23 +08:00
有点意思 马克一下
|
38
neoblackcap 2018-11-08 17:10:29 +08:00
理论上这个东西要优化,那么就得把数据库的查询优化器提到应用层,要不然上面所说的 N+1 问题,性能就会马上爆炸
|
39
eloah 2018-11-08 18:26:16 +08:00
之前用了一下,很多蛋疼的地方
比如复杂的权限控制,比如还要自己弄 data loader |
40
TommyLemon 2018-11-08 18:29:59 +08:00
@eloah 哈哈,可以看下 APIJSON,提供自动化的权限控制,自动化 join,#9 楼 #21 楼有详细对比
|
41
buhi 2018-11-08 18:46:16 +08:00
N+1 也不是很难解决, 二三十行代码就能变成 1+1
|
42
TommyLemon 2018-11-08 18:50:39 +08:00
|
43
buhi 2018-11-08 18:55:12 +08:00
没搞懂问题在哪儿? 你不是本来就得对每个要查询的 Type 写一个 resolve 吗?
|
44
MeteorCat 2018-11-08 18:57:48 +08:00 via Android
性能和效率的博弈
|
45
TommyLemon 2018-11-08 19:00:16 +08:00
要写大量逻辑重复又不好抽象的代码,就是问题啊
|
46
TommyLemon 2018-11-08 19:08:02 +08:00
@TommyLemon
从 graphql-js 摘取片段代码 github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsSchema.js ```js const humanType = new GraphQLObjectType({ name: 'Human', description: 'A humanoid creature in the Star Wars universe.', fields: () => ({ id: { type: GraphQLNonNull(GraphQLString), description: 'The id of the human.', }, name: { type: GraphQLString, description: 'The name of the human.', }, friends: { type: GraphQLList(characterInterface), description: 'The friends of the human, or an empty list if they have none.', resolve: human => getFriends(human), }, appearsIn: { type: GraphQLList(episodeEnum), description: 'Which movies they appear in.', }, homePlanet: { type: GraphQLString, description: 'The home planet of the human, or null if unknown.', }, secretBackstory: { type: GraphQLString, description: 'Where are they from and how they came to be who they are.', resolve() { throw new Error('secretBackstory is secret.'); }, }, }), interfaces: [characterInterface], }); const queryType = new GraphQLObjectType({ name: 'Query', fields: () => ({ hero: { type: characterInterface, args: { episode: { description: 'If omitted, returns the hero of the whole saga. ' + 'If provided, returns the hero of that particular episode.', type: episodeEnum, }, }, resolve: (root, { episode }) => getHero(episode), }, human: { type: humanType, args: { id: { description: 'id of the human', type: GraphQLNonNull(GraphQLString), }, }, resolve: (root, { id }) => getHuman(id), }, droid: { type: droidType, args: { id: { description: 'id of the droid', type: GraphQLNonNull(GraphQLString), }, }, resolve: (root, { id }) => getDroid(id), }, }), }); ``` 从 dataloader 摘取片段代码 github.com/facebook/dataloader/blob/master/examples/SQL.md ```js var DataLoader = require('dataloader'); var sqlite3 = require('sqlite3'); var db = new sqlite3.Database('./to/your/db.sql'); // Dispatch a WHERE-IN query, ensuring response has rows in correct order. var userLoader = new DataLoader(ids => { var params = ids.map(id => '?' ).join(); var query = `SELECT * FROM users WHERE id IN (${params})`; return queryLoader.load([query, ids]).then( rows => ids.map( id => rows.find(row => row.id === id) || new Error(`Row not found: ${id}`) ) ); }); // Parallelize all queries, but do not cache. var queryLoader = new DataLoader(queries => new Promise(resolve => { var waitingOn = queries.length; var results = []; db.parallelize(() => { queries.forEach((query, index) => { db.all.apply(db, query.concat((error, result) => { results[index] = error || result; if (--waitingOn === 0) { resolve(results); } })); }); }); }), { cache: false }); // Usage var promise1 = userLoader.load('1234'); var promise2 = userLoader.load('5678'); Promise.all([ promise1, promise2 ]).then(([ user1, user2]) => { console.log(user1, user2); }); ``` |
47
mingyun 2019-01-06 16:02:21 +08:00
@TommyLemon GraphQL 这么 6
|
48
karllynn 2019-04-03 12:55:27 +08:00
这个东西感觉只有内部系统可能会用一下,前端的权限太高了,而且性能很难保证,个人不看好。而且我记得以前就有项目可以前端直接写 sql 了。
|