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

chenge · 发布于 2016年12月25日 · 最后由 TommyLemon 回复于 2017年07月31日 · 1265 次阅读
4215

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

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

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

共收到 11 条回复
1

三年换两?

2880

还有个 JsonAPI, 都不看好

2575

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

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

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

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

775

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

7386

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

17004

不如jsonapi

96

你好,感谢你的关注。
查询:
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":{
        "@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://139.196.140.118

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

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

96
775nouse 回复

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

96
2575darkbaby123 回复

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

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