Skip to content

让接口和文档见鬼去吧!客户端定义服务端返回JSON的结构!Let interfaces and documents go to hell! Clients define JSON structures which server returned!

master
Go to file
Code
This branch is 1730 commits behind Tencent:master.

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 

README.md

APIJSON

English Document

APIJSON是一种JSON传输结构协议。

客户端可以定义任何JSON结构去向服务端发起请求,服务端就会返回对应结构的JSON字符串,所求即所得。
一次请求任意结构任意数据,方便灵活,不需要专门接口或多次请求。
支持增删改查、模糊搜索、远程函数调用等。还能去除重复数据,节省流量提高速度!

从此HTTP传输JSON数据没有接口,更不需要文档!
客户端再也不用和服务端沟通接口或文档问题了!再也不会被文档各种错误坑了!
服务端再也不用为了兼容旧版客户端写新版接口和文档了!再也不会被客户端随时随地没完没了地烦了!

举个栗子(查询类似微信朋友圈动态列表):

请求:

{
    "[]": {                                               //请求一个array
        "page": 0,                                    //array条件
        "count": 2,        
        "User": {                                      //请求查询名为User的table,返回名为User的JSONObject
            "sex": 0                                   //object条件
        },
        "Moment": {
            "userId@": “/User/id”             //缺省依赖路径,从同级object的路径开始
        },
        "Comment[]": {                           //请求一个名为Comment的array 
            "page": 0,
            "count": 2,
            "Comment": {
                 "momentId@": “[]/Moment/id”   //完整依赖路径
             }
        }
    }
}

点击这里测试

返回:

{
    "[]":{
        "0":{
            "User":{
                "id":38710,
                "sex":0,
                "phone":"1300038710",
                "name":"Name-38710",
                "head":"http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000"
            },
            "Moment":{
                "id":470,
                "title":"Title-470",
                "content":"This is a Content...-470",
                "userId":38710,
                "pictureList":["http://static.oschina.net/uploads/user/585/1170143_50.jpg?t=1390226446000"]
            },
            "Comment[]":{
                "0":{
                    "Comment":{
                        "id":4,
                        "parentId":0,
                        "momentId":470,
                        "userId":310,
                        "targetUserId":14604,
                        "content":"This is a Content...-4",
                        "targetUserName":"targetUserName-14604",
                        "userName":"userName-93781"
                    }
                },
                "1":{
                    "Comment":{
                        "id":22,
                        "parentId":221,
                        "momentId":470,
                        "userId":332,
                        "targetUserId":5904,
                        "content":"This is a Content...-22",
                        "targetUserName":"targetUserName-5904",
                        "userName":"userName-11679"
                    }
                }
            }
        },
        "1":{
            "User":{
                "id":70793,
                "sex":0,
                "phone":"1300070793",
                "name":"Name-70793",
                "head":"http://static.oschina.net/uploads/user/1174/2348263_50.png?t=1439773471000"
            },
            "Moment":{
                "id":170,
                "title":"Title-73",
                "content":"This is a Content...-73",
                "userId":70793,
                "pictureList":["http://my.oschina.net/img/portrait.gif?t=1451961935000"]
            },
            "Comment[]":{
                "0":{
                    "Comment":{
                        "id":44,
                        "parentId":0,
                        "momentId":170,
                        "userId":7073,
                        "targetUserId":6378,
                        "content":"This is a Content...-44",
                        "targetUserName":"targetUserName-6378",
                        "userName":"userName-88645"
                    }
                },
                "1":{
                    "Comment":{
                        "id":54,
                        "parentId":0,
                        "momentId":170,
                        "userId":3,
                        "targetUserId":62122,
                        "content":"This is a Content...-54",
                        "targetUserName":"targetUserName-62122",
                        "userName":"userName-82381"
                    }
                }
            }
        }
    }
}

功能符

 键值对格式 功能与作用 使用示例
"key[]":{},后面是标准的JSONObject 查询数组 "User[]":{"User":{"sex":1}},查询性别为女的一个的User数组,请求完成后会变为 "User[]":{"0":{"User":{"id":38710,"sex":1,"name":"Tommy"...}}, "1":{"User":{"id":82001,"sex":1,"name":"Lemon"...}} ...}
"key{}":[],后面是标准的JSONArray,作为key可取的范围 匹配范围 "id{}":[38710,82001,70793],查询id符合38710,82001,70793中任意一个的Object。一般用于查询一个数组。请求{"[]":{"User":{"id{}":[38710,82001,70793]}}}会返回一个User数组,例如上面那个。
"key()":"函数表达式", 函数表达式为 function(Type0:value0,Type1:value1...) 远程调用函数 "isPraised()":"contains(Collection:praiseUserIdList,userId)",请求完成后会调用 boolean contains(Collection collection, Object object) 函数,然后变为 "isPraised":true 这种(假设点赞用户id列表包含了userId,即这个User点了赞)。函数参数类型为Object时可用 value 替代 Object:value。
"key@":"依赖路径",依赖路径为用/分隔的字符串 依赖引用 "userId@":"/User/id",userId依赖引用同级User内的id值,假设id=1,则请求完成后会变成 "userId":1
"key$":"SQL搜索表达式",任意标准SQL搜索表达式字符串,如 %key%, %k%e%y% 等 模糊搜索 "name$":"%Tommy%",搜索包含Tommy的名字。一般用于查询一个数组。请求 {"[]":{"User":{"name$":"%Tommy%"}}} 会返回name包含"Tommy"的User数组。
"@key":key指定类型的Object @key为JSONObject中的关键字,作用各不相同,但都不作为查询匹配条件 ① 只查询id,sex,name这几列并且请求结果也按照这个顺序:
"@columns":"id,sex,name"
返回
{
  "id":1,
  "sex":0,
  "name":"Lemon"
}
...
② 从pictureList获取第0张图片作为头像:
{
  "pictureList":["url0","url1"],
  "@position":0, //这里@position为自定义关键词
  "head()":"get(Collection:pictureList,Object:@position)"
}
返回
{
  "pictureList":["url0","url1"],
  "head":"url0"
}
...

对比传统HTTP传输方式

开发流程 传统方式 APIJSON
接口传输 等服务端编辑接口,然后更新文档,客户端再按照文档编辑请求和解析代码 客户端按照自己的需求编辑请求和解析代码。没有接口,更不需要文档!客户端再也不用和服务端沟通接口或文档问题了!
兼容旧版 服务端增加新接口,用v2表示第2版接口,然后更新文档 什么都不用做!
客户端请求 传统方式 APIJSON
要求 客户端按照文档在对应url后面拼接键值对 客户端按照自己的需求在固定url后拼接JSON
结构 base_url/lowercase_table_name?key0=value0&key1=value1...
&currentUserId=100&loginPassword=1234

其中currentUserId和loginPassword只在请求部分接口时需要
base_url/{TableName0:{key0:value0, key1:value1 ...}, TableName1:{...}...
, currentUserId:100, loginPassword:1234}

其中currentUserId和loginPassword只在请求部分接口时需要
URL 不同的请求对应不同的url 相同的请求方法(GET,POST等)都用同一个url
键值对 key=value key:value
服务端操作 传统方式 APIJSON
解析和返回 取出键值对,把键值对作为条件用预设的的方式去查询数据库,最后封装JSON并返回给客户端 把RequestParser#parse方法的返回值返回给客户端就行
返回JSON结构的设定方式 由服务端设定,客户端不能修改 由客户端设定,服务端不能修改
客户端解析 传统方式 APIJSON
查看方式 查文档或等请求成功后看log 看请求就行,所求即所得。也可以等请求成功后看log
方法 解析JSONObject 可以用JSONResponse解析JSONObject或传统方式
客户端对应不同需求的请求 传统方式 APIJSON
User http://localhost:8080/get/user?id=1 http://localhost:8080/get/{"User":{"id":1}}
Moment和对应的User 分两次请求
Moment: http://localhost:8080/get/moment?userId=1
User: http://localhost:8080/get/user?id=1
http://localhost:8080/get/{"Moment":{"id":1}, "User":{"id@":"Moment/userId"}}
User列表 http://localhost:8080/get/user/list?page=0&count=3&sex=0 http://localhost:8080/get/{"[]":{"page":0, "count":3, "User":{"sex":0}}}
Moment列表,每个Moment包括发布者User和前3条Comment Moment里必须有User的Object和Comment的Array
http://localhost:8080/get/moment/list?page=0&count=3&commentCount=3
http://localhost:8080/get/{"[]":{"page":0, "count":3, "Moment":{}, "User":{"momentId@":"/Moment/id"}, "[]":{"count":3, "Comment":{"momentId@":"[]/Moment/id"}}}}
User发布的Moment列表,每个Moment包括发布者User和前3条Comment http://localhost:8080/get/moment/list?page=0&count=3&commentCount=3&userId=1 有以下几种方法:
①把以上请求里的"Moment":{}, "User":{"momentId@":"/Moment/id"}改为"Moment":{"userId":1}, "User":{"id":1}

②或这样省去4条重复User
http://localhost:8080/get/{"User":{"id":1}, "[]":{"page":0, "count":3, "Moment":{"userId":1}, "[]":{"count":3, "Comment":{"momentId@":"[]/Moment/id"}}}}

③如果User之前已经获取到了,还可以这样省去所有重复User
http://localhost:8080/get/{"[]":{"page":0, "count":3, "Moment":{"userId":1}, "[]":{"count":3, "Comment":{"momentId@":"[]/Moment/id"}}}}
服务端对应不同请求的返回结果 传统方式 APIJSON
User {"status":200, "message":"success", "data":{"id":1, "name":"xxx"...}} {"status":200, "message":"success", "User":{"id":1, "name":"xxx"...}}
User和对应的Moment 分别返回两次请求的结果
User: {"status":200, "message":"success", "data":{"id":1, "name":"xxx"...}}
Moment: {"status":200, "message":"success", "data":{"id":1, "name":"xxx"...}}
{"status":200, "message":"success", "User":{"id":1, "name":"xxx"...}, "Moment":{"id":1, "content":"xxx"...}}
User列表 {"status":200, "message":"success", "data":[{"id":1, "name":"xxx"...}, {"id":2...}...]} {"status":200, "message":"success", "[]":{"0":{"User":{"id":1, "name":"xxx"...}}, "1":{"User":{"id":2...}}...}}
Moment列表,每个Moment包括发布者User和前3条Comment {"status":200, "message":"success", "data":[{"id":1, "content":"xxx"..., "User":{...}, "Comment":[...]}, {"id":2...}...]} {"status":200, "message":"success", "[]":{"0":{"Moment":{"id":1, "content":"xxx"...}, "User":{...}, "[]":{"0":{"Comment":{...}...}}}, "1":{...}...}}
User发布的Moment列表,每个Moment包括发布者User和前3条Comment {"status":200, "message":"success", "data":[{"id":1, "content":"xxx"..., "User":{...}, "Comment":[...]}, {"id":2...}...]} 以上不同请求方法的结果:
①{"status":200, "message":"success", "[]":{"0":{"User":{"id":1, "name":"xxx"...}, "Moment":{...}, "[]":{"0":{"Comment":{...}...}}}, "1":{...}...}}

②{"status":200, "message":"success", "User":{...}, "[]":{"0":{"Moment":{"id":1, "content":"xxx"...}, "[]":{"0":{"Comment":{...}...}}}, "1":{...}...}}

③{"status":200, "message":"success", "[]":{"0":{"Moment":{"id":1, "content":"xxx"...}, "[]":{"0":{"Comment":{...}...}}}, "1":{...}...}}

(注:APIJSON不需要接口、文档及兼容旧版客户端的特性仅针对GET和HEAD请求,好在大部分请求都是GET请求)

使用方法

1.下载后解压APIJSON工程

Clone or download > Download ZIP > 解压到一个路径并记住这个路径。

你可以跳过步骤2和步骤3,用我的服务器IP地址 139.196.140.118:8080 来测试服务端对客户端请求的返回结果。

2.导入MySQL table文件

服务端需要MySQL Server和MySQLWorkbench,没有安装的都先下载安装一个。
我的配置是Windows 7 + MySQL Community Server 5.7.16 + MySQLWorkbench 6.3.7 和 OSX EI Capitan + MySQL Community Server 5.7.16 + MySQLWorkbench 6.3.8,其中系统和软件都是64位的。

启动MySQLWorkbench > 进入一个Connection > 点击Server菜单 > Data Import > 选择刚才解压路径下的APIJSON-Master/table > Start Import > 刷新SCHEMAS, 左下方sys/tables会出现添加的table。

3.用Eclipse for JavaEE或IntellIJ IDEA Ultimate运行服务端工程

如果以上编辑器一个都没安装,运行前先下载安装一个。
我的配置是Windows 7 + JDK 1.7.0_71 + Eclipse 4.6.1 + IntellIJ 2016.3 和 OSX EI Capitan + JDK 1.8.0_91 + Eclipse 4.6.1 + IntellIJ 2016.2.5

Eclipse for JavaEE

1.导入
File > Import > Maven > Existing Maven Projects > Next > Browse > 选择刚才解压路径下的APIJSON-Master/APIJSON(Server)/APIJSON(Eclipse_JEE) > Finish

2.运行
Run > Run As > Java Application > 选择APIJSONApplication > OK

IntellIJ IDEA Ultimate

1.导入
Open > 选择刚才解压路径下的APIJSON-Master/APIJSON(Server)/APIJSON(Idea) > OK

2.运行
Run > Run APIJSONApplication

4.用ADT Bundle或Android Studio运行客户端工程

可以跳过这个步骤,直接下载下方提供的客户端App。

如果以上编辑器一个都没安装,运行前先下载安装一个。
我的配置是Windows 7 + JDK 1.7.0_71 + ADT Bundle 20140702 + Android Studio 2.2 和 OSX EI Capitan +(JDK 1.7.0_71 + ADT Bundle 20140702)+(JDK 1.8.0_91 + Android Studio 2.1.2),其中系统和软件都是64位的。

ADT Bundle

1.导入
File > Import > Android > Existing Android Code Into Workspace > Next > Browse > 选择刚才解压路径下的APIJSON-Master/APIJSON(Android)/APIJSON(ADT) > Finish

2.运行
Run > Run As > Android Application

Android Studio

1.导入
Open an existing Android Studio project > 选择刚才解压路径下的APIJSON-Master/APIJSON(Android)/APIJSON(AndroidStudio) > OK

2.运行
Run > Run app

5.操作客户端App

选择发送APIJSON请求并等待显示结果。
如果默认url不可用,修改为一个可用的,比如正在运行APIJSON服务端工程的电脑的IPV4地址,然后点击查询按钮重新请求。

下载试用客户端App

APIJSONClientApp.apk

关于APIJSON如果你有任何问题或建议,都可以发我邮件 tommylemon@qq.com.

更新日志

https://github.com/TommyLemon/APIJSON/commits/master

欢迎Star,欢迎Fork

https://github.com/TommyLemon/APIJSON

APIJSON,让接口见鬼去吧!

About

让接口和文档见鬼去吧!客户端定义服务端返回JSON的结构!Let interfaces and documents go to hell! Clients define JSON structures which server returned!

Resources

License

Releases

No releases published

Packages

No packages published
You can’t perform that action at this time.