Android APIJson,类似 GraphQL,大家评估一下

chenge · 2016年12月25日 · 最后由 TommyLemon 回复于 2021年01月19日 · 18762 次阅读

据作者说比 GraphQL 简单很多,功能类似,目前支持 java。

如果真能做到,后端将大幅度简化了。

https://my.oschina.net/u/2437072/blog/805459

三年换两?

还有个 JsonAPI, 都不看好

思路还是 GraphQL 那一套,那我更宁愿去试试 GraphQL/Falcor。而且它的简单基于一个假设:JSON resource 结构跟数据库的表结构一致。现实中稍微复杂点的模型都不是这样的。所以 -- 不怎么看好。只说说我还算了解的 JSON API 和 GraphQL。

JSON API 适合粗粒度场景,是 REST 思路的延伸,各方面都有所考虑,对处理 relationship 有自己的一套解法。如果自己定义 API 规范有些想不清楚的地方,这个规范值得参考,但不见得值得使用。不过如果非要在同类规范(HAL, Siren 等)中选一个,我更愿意选择它。最后,如果使用 Ember + Ember Data 的话,这个规范还是推荐的。

GraphQL 没实际写过,感觉适合细粒度场景,适合前端频繁变化的应用,配合 Relay 和 React 可以有效的整合各个组件中的请求。我个人更喜欢这种方式的数据层,屏蔽了发起哪些查询和何时发起查询等细节。

最后,写 API 本来就是个体力活,这部分本该自动化一点。

GraphQL 的可维护性我表示怀疑,搞这么复杂还不如 RPC 呢,一段复杂的 SQL 不比 RPC 代码好维护。

#1 楼 @Rei 为什么你的回复永远给我一种“我懒得说第二句”的高冷既视感。

不如 jsonapi

你好,感谢你的关注。
查询:
GraphQL-半自动化,只有过滤字段实现了自动化,且字段需要手动 resolve。
APIJSON-完全自动化,任意结构任意内容,只要数据库里有。

兼容性:
GraphQL-GraphQL 特定格式,只能用 GraphQL Server,Client,Web 全套。
APIJSON-标准 JSON 格式,能用 JSON 的地方就能用 APIJSON。

为了公平起见,以下 GraphQL 的所有示例都出自官方文档及代码。

1.查询条件
GraphQL:

table(key0:value0,key1:value1,...) {
}
{
  user(id: 4) {
    id
    name
  }
}

APIJSON:

Table: {
    key0:value0,
    key1:value1,
    ...
}
{
    "User":{
        "id":38710
    }
}

2.返回字段
GraphQL:
只返回已声明字段

{
    key0
    key1
    ...
}
{
  user(id: 4) {
    id
    name
  }
}

APIJSON:
默认返回全部,可加上以下条件限制

"@column":"key0,key1,..."
{
    "User":{
        "id":38710,
        "@column":"id,name"
    }
}

3.查询数组:
GraphQL:
需要后端在 schema 中手动 resolve

query noFragments {
  user(id: 4) {
    friends(first: 10) {
      id
      name
    }
  }
}

APIJSON:
"[]":{} 自动解析

{
    "[]":{
        "count":10,
        "User":{
        }
    }
}

4.关联查询:
需要后端在 schema 中手动 resolve 关联
GraphQL:

query inlineFragmentTyping {
  profiles(handles: ["zuck", "cocacola"]) {
    handle
    ... on User {
      friends {
        count
      }
    }
    ... on Page {
      likers {
        count
      }
    }
  }
}

APIJSON:
"key@":"key0/key1/.../targetKey" 自动解析

{
    "[]": {
        "User": {
            "name$": ["Strong", "Mike"]
        },
        "Moment": {
            "userId@": "[]/User/id"
        }
    }
}

5.后端定义结构
GraphQL:
读、写操作都需要,代码中,且字段要手动 resolve。
Node.js

var schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      hello: {
        type: GraphQLString,
        resolve() {
          return 'world';
        }
      }
    }
  })
});

Java

GraphQLObjectType queryType = newObject()
                        .name("helloWorldQuery")
                        .field(newFieldDefinition()
                                .type(GraphQLString)
                                .name("hello")
                                .staticValue("world"))
                        .build();

        GraphQLSchema schema = GraphQLSchema.newSchema()
                        .query(queryType)
                        .build();

APIJSON:
只有写操作才需要,自动解析自动校验,而且是在数据库 Request 表中定义,完全可视化。

{
    "Moment":{
        "DISALLOW":"id",
        "NECESSARY":"userId,pictureList"
    }
}

6.前端查询灵活性
GraphQL:
1.所有结构都要后端先定义,前端/客户端才能按照已定义结构查询。
2.多层嵌套需要后端在结构外声明内部结构,不够直观,Request 和 Response 不能完全对应 (Request 少了内层结构)。

后端定义:

const UserType = new GraphQLType({
    name:'User",
    fields:{
        id:{
            type:GraphQLInt
        },
        name:{
            type:GraphQLString
        }
    }
})

const CommentType = new GraphQLType({
    name:'Comment",
    fields:{
        id:{
            type:GraphQLInt
        },
        toId:{
            type:GraphQLInt
        },
        userId:{
            type:GraphQLInt
        },
        content:{
            type:GraphQLString
        }
    }
})


const MomentType = new GraphQLType({
    name:'Moment",
    fields:{
        id:{
            type:GraphQLInt
        },
        userId:{
            type:GraphQLInt
        },
        title:{
            type:GraphQLString
        },
        content:{
            type:GraphQLString
        },
        user:{
            type:new GraphQLObject(UserType)
            resolve:(moment) => getUserById(userId)
        },
        comments:{
           type:new GraphQLList(CommentType),
           resolve:(moment) => moment.commentIds.map(id => getCommentById(id))
        }
    }
})


function getUserById(id) {
    //查询User...
    return new UserType(id) //这里只是模拟,实际代码一般会比较多
}

function getCommentById(id) {
    //查询Comment...
    return new CommentType(id) //这里只是模拟,实际代码一般会比较多
}

前端请求:

query momentFragmentTyping {
     moments(first: 10, text: "a") {
            id
            userId
            title
            content
            user {
                id
                name
            }
            comments(first: 2) {
                    id
                    toId
                    userId
                    content
            }
     }
})

注:实在找不到官方的,群里问出了这个。

APIJSON:
1) 不需要后端定义,只要 类声明 + 权限注解 + 权限注册 3 行代码配置 Model 允许的操作及对应的角色。
3) 可任意组合、任意嵌套,Request 和 Response 完全对应。

后端定义:

//注册表并添加权限,以下都用默认
@MethodAccess
public class User {
}

@MethodAccess
public class Comment {
}

@MethodAccess
public class Moment {
}

//AccessVerifier内添加权限
accessMap.put(User.class.getSimpleName(), getAccessMap(User.class.getAnnotation(MethodAccess.class)));
accessMap.put(Moment.class.getSimpleName(), getAccessMap(Moment.class.getAnnotation(MethodAccess.class)));
accessMap.put(Comment.class.getSimpleName(), getAccessMap(Comment.class.getAnnotation(MethodAccess.class)));

前端请求:

{
  "[]":{                             //请求一个数组
    "page":0,                        //数组条件
    "count":2,
    "Moment":{                       //请求一个名为Moment的对象
      "content$":"%a%"               //对象条件,搜索content中包含a的动态
    },
    "User":{
      "id@":"/Moment/userId",        //缺省依赖路径,从所处容器的父容器路径开始
      "@column":"id,name,head"       //指定返回字段
    },
    "Comment[]":{                    //请求一个名为Comment的数组,并去除Comment包装
      "count":2,
      "Comment":{
        "momentId@":"[]/Moment/id"   //完整依赖路径
      }
    }
  }
}

7.前端写操作请求
GraphQL:
代码中定义 mutation schema。

mutation {
  likeStory(storyID: 12345) {
    story {
      likeCount
    }
  }
}

APIJSON:
操作单条记录必传"id":Long,操作多条记录必传"id{}":[Long],还有自动化权限校验,保证安全性。

{
    "Moment":{
        "id":12,
        "praiseUserIdList+":[
            38710
        ]
    }
}

等我有时间再发篇博文,做一个详细的比较。
APIJSON 目前有 Java Server,Android,JavaScript 3 种实现,如果要和 GraphQL 比,这几种语言随便挑。

APIJSON 在线测试
http://39.108.143.172

APIJSON 项目主页
https://github.com/TommyLemon/APIJSON

欢迎使用、建议、吐槽、反馈 ^_^

nouse 回复

确实很复杂,概念就很多很绕了,schema,mutation,Subscription,Source Stream,Notation Conventions... 而且 Request 和 Schema 并不是严格对应,尤其是多层嵌套的时候,Schema 内层对象得通过外部函数调用来获取。 字段关联居然要手动 resolve,前端发的每个 Request 都必须在后端先有对应的 Schema 声明。 GraphQL 并没有替代 REST,而是在 Web/Client 到 REST Sever 中间用 GraphQL Server 做了个中间层,最后还是调 REST API.

darkbaby123 回复

除了目标一致,其它完全不一样,不管是思路还是实现。 GraphQL 是查询语言,APIJSON 是 JSON 传输结构协议 (也包括内容)。 用 GraphQL 就要学习一堆概念和语法,前端要后端要写一大堆 schema 才能用对应 schema 结构的特定格式来请求,正因为 GraphQL 格式特殊,整个后端都要重写。 而 APIJSON 只是一个简单的 JSON 对应协议,采用标准且通用的的 JSON 格式,只有少数几个简单的概念,没有所谓的语法,Request 和 Response 的结构严格对应,支持任意组合任意嵌套任意内容,并且还能和原来的 RESTful API 无缝兼容,几乎无迁移成本。 可以试试 https://github.com/TommyLemon/APIJSON

完爆 Facebook/GraphQL,APIJSON 全方位对比解析 (一)-基础功能 https://juejin.im/post/5ae80edd51882567277433cf

完爆 Facebook/GraphQL,APIJSON 全方位对比解析 (二)-权限控制 https://juejin.im/post/5b17518c6fb9a01e75463096

完爆 Facebook/GraphQL,APIJSON 全方位对比解析 (三)-表关联查询 https://juejin.im/entry/5b4ff88f6fb9a04f914a8df5

腾讯开源 APIJSON 连创五个第一

腾讯第一个码云推荐项目,// 其它最早创建的是 TencentOS-tiny(码云) 2019.8.23

腾讯第一个码云 GVP 项目,// 其它最早创建的是 TencentOS-tiny(码云) 2019.8.23

腾讯码云官方所有项目中 Star 第一,// 其它最高是 TencentOS-tiny(码云) 272 个 Star

腾讯所有后端开发项目中 Star 第一,// 其它最高是 libco(GitHub) 5.8K Star

腾讯所有网络编程项目中 Star 第一。// 其它最高是 TencentOS-tiny(GitHub) 4.7K Star

https://www.oschina.net/news/120011

-news

需要 登录 后方可回复, 如果你还没有账号请 注册新账号