【轉】APIJSON,讓介面見鬼去吧!

來源:互聯網
上載者:User

標籤:不同的   個人   span   時間   .com   blog   導致   提示   use   

我:

APIJSON,讓介面和文檔見鬼去吧!

https://github.com/TommyLemon/APIJSON

服務端:

什麼鬼?

用戶端:

APIJSON是啥?

我:

APIJSON是一種JSON傳輸結構協議。

用戶端可以定義任何JSON結構去向服務端發起請求,服務端就會返回對應結構的JSON字串,所求即所得。

一次請求任意結構任意資料,方便靈活,不需要專門介面或多次請求。

支援增刪改查、模糊搜尋、遠程函數調用等。還能去除重複資料,節省流量提高速度!

從此HTTP傳輸JSON資料沒有介面,更不需要文檔!

用戶端再也不用和服務端溝通介面或文檔問題了!再也不會被文檔各種錯誤坑了!

服務端再也不用為了相容舊版用戶端寫新版介面和文檔了!再也不會被用戶端隨時隨地沒完沒了地煩了!


 

用戶端:

這個APIJSON有這麼好?怎麼做到的?

我:

舉個栗子(查詢類似朋友圈動態列表):

請求:


{    "[]": {                               //請求一個array        "page": 0,                        //array條件        "count": 2,                "User": {                         //請求查詢名為User的table,返回名為User的JSONObject            "sex": 0                      //object條件        },        "Moment": {            "[email protected]": “/User/id”         //預設依賴路徑,從同級object的路徑開始        },        "Comment[]": {                    //請求一個名為Comment的array             "page": 0,            "count": 2,            "Comment": {                 "[email protected]": “[]/Moment/id”  //完整依賴路徑             }        }    }}

 

點擊這裡測試

返回:

{    "[]":[        {            "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[]":[                {                    "Comment":{                        "id":4,                        "parentId":0,                        "momentId":470,                        "userId":310,                        "targetUserId":14604,                        "content":"This is a Content...-4",                        "targetUserName":"targetUserName-14604",                        "userName":"userName-93781"                    }                },                {                    "Comment":{                        "id":22,                        "parentId":221,                        "momentId":470,                        "userId":332,                        "targetUserId":5904,                        "content":"This is a Content...-22",                        "targetUserName":"targetUserName-5904",                        "userName":"userName-11679"                    }                }            ]        },        {            "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[]":[                {                    "Comment":{                        "id":44,                        "parentId":0,                        "momentId":170,                        "userId":7073,                        "targetUserId":6378,                        "content":"This is a Content...-44",                        "targetUserName":"targetUserName-6378",                        "userName":"userName-88645"                    }                },                {                    "Comment":{                        "id":54,                        "parentId":0,                        "momentId":170,                        "userId":3,                        "targetUserId":62122,                        "content":"This is a Content...-54",                        "targetUserName":"targetUserName-62122",                        "userName":"userName-82381"                    }                }            ]        }    ]}

  

用戶端:

確實是一目瞭然,不用看文檔了啊!

我被文檔坑過很多次了都,文檔多寫或少寫了一個欄位,欄位寫錯或多個空格,或者欄位類型寫錯,都不知道浪費了多少調試和溝通時間!

有時候上頭用app出了問題把我們叫過去,調試半天才發現原來是服務端改了介面!而且並沒有及時通知我們!

有一次上頭糾結要不要把單層評論改成QQ那種多級評論,自己按照以前的介面寫了demo示範給上頭看,上頭很滿意決定實現需求,結果後端都沒和我商量自己改了介面返回的json結構,導致我這邊不得不重構解析代碼,真是醉了!

我:

用APIJSON就可以自己按需定製返回的JSON結構,沒有介面,沒有文檔,就不會被文檔坑了,也不會有你說的後端拍腦袋定JSON結構導致的用戶端重構問題了哈哈!

用戶端:

Nice!

服務端:

部分介面需要currentUserId和loginPassword的,你怎麼搞?

我:

直接在最外層傳,例如:

{    "currentUserId":100,    "loginPassword":1234,    "User":{        "id":1    }}

 

服務端:

返回的狀態代碼和提示資訊放哪?

我:

也是在最外層,例如對以上請求的返回結果:

{    "status":200,    "message":"success",    "User":{        "id":"1",        "sex":"0",        "phone":"1234567890",        "name":"Tommy",        "head":"http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000"    }}

 

用戶端:

一次請求任意結構任意資料,方便靈活,不需要專門介面或多次請求?

以前我做了一個介面,上半部分是使用者的資訊,下半部分是他最近的動態,最多顯示3個,類似於的詳細資料。

我需要分別請求兩次:

User:

http://www.aaa.com/get/user?id=100

 

Moment列表:

http://www.aaa.com/get/moment/list?page=0&count=3&userId=100

 

現在是不是可以這樣:

User和Moment列表:

http://www.aaa.com/get/{"User":{"id":100}, "[]":{"page":0, "count":3, "Moment":{"userId":100}}}

 

我:

對的,就是這樣。

用戶端:

好的。那重複資料怎麼去除呢?

我:

比如QQ空間,裡面有一個動態列表,每條動態裡都有User和對應的動態內容Moment。

如果你進入一個人的空間,那就都是他的動態。

用傳統的方式返回的列表資料裡,每條動態裡都包含同樣的User,造成了資料重複:

請求:

http://www.aaa.com/get/moment/list?page=0&count=5&userId=100

 

返回:

{    "status":200,    "message":"success",    "data":[        {            "id":1,            "content":"xxx1",            ...,            "User":{                "id":100,                "name":"Tommy",                ...            }        },        {            "id":2,            "content":"xxx2",            ...,            "User":{                "id":100,                "name":"Tommy",                ...            }        },        ...    ]}

 

有5條重複的User。

而使用APIJSON可以這樣省去4個重複User:

請求:

http://www.aaa.com/get/{"User":{"id":100}, "[]":{"page":0, "count":5, "Moment":{"userId":100}}}

 

返回:

{    "status":200,    "message":"success",    "User":{        "id":100,        "name":"Tommy",        ...    },    "[]":[        {            "Moment":{                "id":1,                "content":"xxx1",                ...            }        },        {            "Moment":{                "id":2,                "content":"xxx2",                ...            }        },        ...    ]}

 

如果之前已經擷取到這個User了,還可以這樣省去所有重複User:

請求:

http://www.aaa.com/get/{"[]":{"page":0, "count":5, "Moment":{"userId":100}}}

 

返回:

{    "status":200,    "message":"success",    "[]":[        {            "Moment":{                "id":1,                "content":"xxx1",                ...            }        },        {            "Moment":{                "id":2,                "content":"xxx2",                ...            }        },        ...    ]}

 

用戶端:

傳統方式也可以服務端在介面增加一個返回格式欄位,根據這個欄位來決定是否去除重複User啊

我:

確實,不過這會導致以下問題:

1.服務端要新增欄位和判斷欄位來返回不同資料的代碼。

2.服務端要在文檔裡增加相關說明。

3.這個功能不一定用得上,因為用戶端的UI需求往往很容易變化,導致缺少使用這個功能的條件,為了一兩個版本去讓服務端和用戶端都折騰不值得。

而使用APIJSON就沒這些問題,因為根本不需要介面或文檔!而且是否去重只看用戶端的意願,服務端什麼都不用做。

用戶端:

這樣啊,贊!

哦對了,APIJSON相比傳統方式有沒有缺少的功能啊?

我:

傳統方式能做的APIJSON都能做。

用戶端和服務端的http json互動:
用戶端 - 封裝request -> 服務端 - 解析request - 產生response -> 用戶端 - 解析response

傳統方式request:

base_url/lowercase_table_name?key0=value0&key1=value1...

 

APIJSON request:

base_url/{TableName:{key0:value0, key1:value1...}}

 

TableName對應lowercase_table_name,key:value對應key=value,都是嚴格對應的,所以傳統方式request裡包含的資訊APIJSON request一樣可以包含,傳統方式能實現的功能APIJSON肯定也都能實現。

用戶端:

好的

服務端:

APIJSON怎麼保證服務端返回給不同版本用戶端的資料一致?

比如我上一個版本一個介面返回的值是a,現在這個版本要對所有版本用戶端返回a+b,用傳統方法只需要服務端把這個介面的傳回值改下就好了,介面和用戶端都不用改。

用APIJSON不就會導致對有些版本返回的是a,有些是a+b,這樣就不能統一了?

我:

APIJSON對請求的解析和響應的操作都是在服務端完成的,對應的是APIJSON(Server)裡的project。

服務端可以攔截到相關請求,比如請求a的值,把原本返回的a改成a+b就能保證對所有版本用戶端返回a+b。也不需要用戶端改代碼,至於介面就更不用管了,因為根本沒有介面。

服務端:

那我要不一致呢?給不同版本用戶端返回不同的值。

我:

首先這種需求是極少的,比如降低電影票的價格,你不能讓新版用戶端裡降價了,上個版本還是原價吧?

真有這種需求也可以通過用戶端在請求裡發送下版本號碼version,服務端根據版本號碼返回不同的值。

服務端:

也是啊。那用APIJSON怎麼做許可權處理?有些資料是要相關許可權才能操作的。比如登入帳號需要登入許可權,付款需要支付許可權。

我:

服務端擷取到用戶端的請求request後,在操作對應的table前用一個許可權驗證類去驗證是否有操作許可權,通過後才允許操作,否則返回錯誤資訊。

許可權驗證類可以是這樣的:

package zuo.biao.apijson.server.sql;import java.rmi.AccessException;import com.alibaba.fastjson.JSONObject;import zuo.biao.apijson.StringUtil;/**許可權驗證類 * @author Lemon */public class AccessVerifyer {    private static final String TAG = "AccessVerifyer: ";    private static final int ACCESS_LOGIN = 1;    private static final int ACCESS_PAY = 2;    public static final String KEY_CURRENT_USER_ID = "currentUserId";    public static final String KEY_LOGIN_PASSWORD = "loginPassword";    public static final String KEY_PAY_PASSWORD = "payPassword";    public static final String[] LOGIN_ACCESS_TABLE_NAMES = {"Work", "Comment"};    public static final String[] PAY_ACCESS_TABLE_NAMES = {"Wallet"};    /**驗證許可權是否通過     * @param request     * @param tableName     * @return     */    public static boolean verify(JSONObject request, String tableName) throws AccessException {        try {            verify(request, getAccessId(tableName));        } catch (AccessException e) {            throw new AccessException(TAG + "verify  tableName = " + tableName + ", error = " + e.getMessage());        }        return true;    }    /**驗證許可權是否通過     * @param request     * @param accessId 可以直接在代碼裡寫ACCESS_LOGIN等,或者建一個Access表。已實現登入密碼自動化處理,不需要寫代碼。     * @return     * @throws AccessException      */    public static boolean verify(JSONObject request, int accessId) throws AccessException {        if (accessId < 0 || request == null) {            return true;        }        long currentUserId = request.getLongValue(KEY_CURRENT_USER_ID);        if (currentUserId <= 0) {            throw new AccessException(TAG + "verify accessId = " + accessId                    + " >>  currentUserId <= 0, currentUserId = " + currentUserId);        }        String password;        switch (accessId) {        case ACCESS_LOGIN:            password = StringUtil.getString(request.getString(KEY_LOGIN_PASSWORD));            if (password.equals(StringUtil.getString(getLoginPassword(currentUserId))) == false) {                throw new AccessException(TAG + "verify accessId = " + accessId                        + " >> currentUserId or loginPassword error"                        + "  currentUserId = " + currentUserId + ", loginPassword = " + password);            }        case ACCESS_PAY:            password = StringUtil.getString(request.getString(KEY_PAY_PASSWORD));            if (password.equals(StringUtil.getString(getPayPassword(currentUserId))) == false) {                throw new AccessException(TAG + "verify accessId = " + accessId                        + " >> currentUserId or payPassword error"                        + "  currentUserId = " + currentUserId + ", payPassword = " + password);            }        default:            return true;        }    }    /**擷取許可權id     * @param tableName     * @return     */    public static int getAccessId(String tableName) {        if (StringUtil.isNotEmpty(tableName, true) == false) {            return -1;        }        for (int i = 0; i < LOGIN_ACCESS_TABLE_NAMES.length; i++) {            if (tableName.equals(LOGIN_ACCESS_TABLE_NAMES[i])) {                return ACCESS_LOGIN;            }        }        for (int i = 0; i < PAY_ACCESS_TABLE_NAMES.length; i++) {            if (tableName.equals(PAY_ACCESS_TABLE_NAMES[i])) {                return ACCESS_PAY;            }        }        return -1;    }    /**擷取登入密碼     * @param userId     * @return     */    public static String getLoginPassword(long userId) {        // TODO 查詢並返回對應userId的登入密碼        return "123456";//僅測試用    }    /**擷取支付密碼     * @param userId     * @return     */    public static String getPayPassword(long currentUserId) {        // TODO 查詢並返回對應userId的支付密碼        return "123456";//僅測試用    }}

 

服務端:

嗯,的確可行。剛看了項目首頁的介紹,感覺APIJSON確實非常強大方便,串連口和文檔都不用寫了,也不會在健身或者陪女朋友看電影時突然接到用戶端的電話了。

不過我還有一個問題,APIJSON是動態拼接SQL的,確實是靈活,但會不會導致SQL注入問題?

我:

APIJSON拼接SQL是在服務端完成的,用戶端是不能直接發送SQL給服務端的。整個資料庫操作都是服務端完全可控的,服務端可攔截危險注入,風險不比傳統方式高。

服務端:

厲害了我的哥!我去下載試試哈哈!

用戶端:

哈哈,我也要試試,請問怎麼擷取源碼?免費的嗎?

我:

已在Github開源,完全免費。

https://github.com/TommyLemon/APIJSON

服務端:

很棒!已Star!

用戶端:

Star +1,順便還Fork了一份研究嘿嘿!另外文檔很詳細贊一個!

我:

有什麼問題或建議可以提issue或者發我郵件 [email protected],大家一起交流探討哈!

服務端:

感覺我以後不用寫一大堆介面了,不需要寫相容代碼了,也不需要寫文檔了。可以專註於資料的處理、監控、統計、分析了哈哈!

用戶端:

我也不用等服務端寫好介面才能請求了,現在自己定製返回的JSON,看請求就知道返回的JSON結構,可以直接寫解析代碼了哈哈!

 

(註:以上是對真實對話的改編)

 

 

APIJSON,讓介面和文檔見鬼去吧!

 

源碼及文檔(記得給個Star哦^_^

 https://github.com/TommyLemon/APIJSON

下載試用(測試伺服器位址:39.108.143.172:8080

APIJSONClientApp.apk

【轉自】https://www.cnblogs.com/LemonStantard/p/6157954.html

 

【轉】APIJSON,讓介面見鬼去吧!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.