• 请不要在回答技术问题时复制粘贴 AI 生成的内容
gzf6
V2EX  ›  程序员

关于 GQL 的新动态,各位怎么看,对前端后端有什么影响

  •  1
     
  •   gzf6 · Nov 8, 2018 · 5743 views
    This topic created in 2768 days ago, the information mentioned may be changed or developed.
    48 replies    2019-04-03 12:55:27 +08:00
    cyril4free
        1
    cyril4free  
       Nov 8, 2018
    隔壁组的同事已经用上了,据说很爽。。免去了前后端对接口参数的困扰。。
    fzleee
        2
    fzleee  
       Nov 8, 2018
    所以,GQL 是个什么东西...
    gzf6
        3
    gzf6  
    OP
       Nov 8, 2018
    heww
        4
    heww  
       Nov 8, 2018 via iPhone
    用起来很爽,不用费什么脑子。但它的 js client 不好用。
    IsaacYoung
        5
    IsaacYoung  
       Nov 8, 2018
    去 redux 化
    reus
        6
    reus  
       Nov 8, 2018
    如果需要高性能,后端就要手写,就没法自动生成代码
    如果自动生成代码,那性能…… 就好像查询不需要开销似的
    关系数据库本质不是图数据库,后端需要实现这两种模型之间的转换,没有简单高效的办法
    反正我是不想做这种东西,除非有图数据库可以替代关系数据库
    trait
        7
    trait  
       Nov 8, 2018 via iPhone
    应该不错,GitHub 的 gql 版本 api 已经有了,正在过渡,Twitter 貌似也在用
    TommyLemon
        8
    TommyLemon  
       Nov 8, 2018   ❤️ 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 部分解决了这些问题,让它们看到了希望
    TommyLemon
        9
    TommyLemon  
       Nov 8, 2018
    @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
    find456789
        10
    find456789  
       Nov 8, 2018
    我是小白

    感觉权限是个问题呀, 比如 没有登陆会员只能查看 3 个字段,vip 能查看 5 个字段, 管理员能查看所有字段, 这在 gql 上是不是很难实现呀?
    TommyLemon
        11
    TommyLemon  
       Nov 8, 2018   ❤️ 1
    @find456789 逻辑不难,但判断要写很多,这里有教程
    juejin.im/post/5b13cda1f265da6e4a6bcfee
    Hilong
        12
    Hilong  
       Nov 8, 2018 via Android
    @TommyLemon 昨天还看到公众号推送去搜索了 下,支持
    asd123456cxz
        13
    asd123456cxz  
       Nov 8, 2018
    @TommyLemon #11 看到老哥推广好多次了。。支持下
    TommyLemon
        14
    TommyLemon  
       Nov 8, 2018
    @Hilong @asd123456cxz 感谢。
    其实我有时也在一些技术群推广 GraphQL,在公司也为 GraphQL 开过分享会。
    不怕对比,就怕大家不知道、不认可 前端定制接口 的做法。
    一部分用户是因为先了解到 GraphQL,然后看不懂、不会用、用起来麻烦,
    后面看到 APIJSON 就转了过来。
    RubyJack
        15
    RubyJack  
       Nov 8, 2018
    性能一塌糊涂
    clino
        16
    clino  
       Nov 8, 2018
    @TommyLemon 能用在 python 后端上吗?
    TommyLemon
        17
    TommyLemon  
       Nov 8, 2018
    @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
    feverzsj
        18
    feverzsj  
       Nov 8, 2018
    前端老是喜欢搞些低能的东西
    TommyLemon
        19
    TommyLemon  
       Nov 8, 2018
    @clino
    目前只有 Java,C#, PHP, Node.js 的后端实现 以及 Android,iOS,JavaScript 的 Demo。
    但 APIJSON 的协议是与语言无关的,可以用 Python 等其它语言实现,可以参考这个引导
    github.com/TommyLemon/APIJSON/issues/38
    buhi
        20
    buhi  
       Nov 8, 2018
    大兄弟, 你怎么保证你这个自己一个人在做的东西就能比 fb 一个大厂在 backup 的东西要好用呢
    TommyLemon
        21
    TommyLemon  
       Nov 8, 2018
    @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 生态了。
    TommyLemon
        22
    TommyLemon  
       Nov 8, 2018
    @TommyLemon 是 APIJSONAuto 比它们好用很多,它们只在支持代码自动补全有优势,
    而 APIJSONAuto 的 自动注释请求、自动生成代码、自动化回归测试(前后对比测试+机器学习测试)是它们都没有的。
    http://apijson。org/
    kran
        23
    kran  
       Nov 8, 2018
    @TommyLemon apijson 怎么和权限认证配合的?
    reus
        24
    reus  
       Nov 8, 2018
    @TommyLemon 我们有自己的方案,不用你这破东西
    likuku
        25
    likuku  
       Nov 8, 2018   ❤️ 2
    刚看到阮一峰的推文: [看到一句妙语。“ GraphQL 的本质是程序员想对 JSON 使用 SQL。”]

    https://twitter.com/ruanyf/status/1060350454238859264
    zjsxwc
        26
    zjsxwc  
       Nov 8, 2018 via Android
    25 楼说的对,本质就是把 json 转 sql
    Narcissu5
        27
    Narcissu5  
       Nov 8, 2018
    第一反应这不就是当年的 web service 么,无非 xml 换成了 json。不知道为什么 facebook 总喜欢重蹈覆辙,react 也是一样的感觉
    buhi
        28
    buhi  
       Nov 8, 2018
    @Narcissu5 react 重蹈了什么?
    TommyLemon
        29
    TommyLemon  
       Nov 8, 2018   ❤️ 1
    @kran 3 行代码即可实现 各种角色 对一张表的 增删改查 默认权限配置,支持通过注解来自定义。
    my.oschina.net/tommylemon/blog/889074
    TommyLemon
        30
    TommyLemon  
       Nov 8, 2018
    @reus 还请您把方案拿出来和“我这破东西”对比下,让大家也长长见识,顺便给与支持
    vipppppp
        31
    vipppppp  
       Nov 8, 2018
    之前还没了解过,刚刚看了一下 GQL,下了个 python 的 demo 看了一下,感觉确实就是 json 转 sql
    至于 apijson 只能说我无福享受啊,毕竟我是个 python 程序员 = =
    TommyLemon
        32
    TommyLemon  
       Nov 8, 2018   ❤️ 1
    @vipppppp 唉,之前有个开发者在 issue 里留言说在做 Python 版:
    “刚刚把单元测试写好。json 的表现层完全自定义,都是为了对应 sql ”
    到现在有 2 个月了也没更新
    github。com/TommyLemon/APIJSON/issues/38
    Narcissu5
        33
    Narcissu5  
       Nov 8, 2018
    @buhi 逻辑和展示高度耦合
    buhi
        34
    buhi  
       Nov 8, 2018
    @Narcissu5 我觉得 react 只是说很容易写出逻辑和展示高度耦合的代码而已, 并不是 react 自己有在鼓励这种写法.
    whypool
        35
    whypool  
       Nov 8, 2018
    fb 出的东西,真的不敢恭维,也就剩下 fb 这大厂在背书了

    如果这是其他公司出的,估计会被喷成翔,即使红透了的 react 也一样
    sologgfun
        36
    sologgfun  
       Nov 8, 2018
    有点意思 马克一下
    reus
        37
    reus  
       Nov 8, 2018
    @Narcissu5 逻辑也是显示逻辑,不耦合干嘛?
    neoblackcap
        38
    neoblackcap  
       Nov 8, 2018
    理论上这个东西要优化,那么就得把数据库的查询优化器提到应用层,要不然上面所说的 N+1 问题,性能就会马上爆炸
    eloah
        39
    eloah  
       Nov 8, 2018
    之前用了一下,很多蛋疼的地方
    比如复杂的权限控制,比如还要自己弄 data loader
    TommyLemon
        40
    TommyLemon  
       Nov 8, 2018
    @eloah 哈哈,可以看下 APIJSON,提供自动化的权限控制,自动化 join,#9 楼 #21 楼有详细对比
    buhi
        41
    buhi  
       Nov 8, 2018
    N+1 也不是很难解决, 二三十行代码就能变成 1+1
    TommyLemon
        42
    TommyLemon  
       Nov 8, 2018
    @buhi 问题是所有需要优化的 Type 都要各自写一个 DataLoader, @eloah 这个兄弟应该深有体会
    buhi
        43
    buhi  
       Nov 8, 2018
    没搞懂问题在哪儿? 你不是本来就得对每个要查询的 Type 写一个 resolve 吗?
    MeteorCat
        44
    MeteorCat  
       Nov 8, 2018 via Android
    性能和效率的博弈
    TommyLemon
        45
    TommyLemon  
       Nov 8, 2018
    要写大量逻辑重复又不好抽象的代码,就是问题啊
    TommyLemon
        46
    TommyLemon  
       Nov 8, 2018
    @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);
    });
    ```
    mingyun
        47
    mingyun  
       Jan 6, 2019
    @TommyLemon GraphQL 这么 6
    karllynn
        48
    karllynn  
       Apr 3, 2019
    这个东西感觉只有内部系统可能会用一下,前端的权限太高了,而且性能很难保证,个人不看好。而且我记得以前就有项目可以前端直接写 sql 了。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2885 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 79ms · UTC 09:14 · PVG 17:14 · LAX 02:14 · JFK 05:14
    ♥ Do have faith in what you're doing.