Me:
Apijson, let the interface and documentation go to hell!
Https://github.com/TommyLemon/APIJSON
Service side:
What the heck?
Client:
What's Apijson?
Me:
Apijson is a JSON transport fabric protocol.
The client can define any JSON structure to go to the server to initiate the request, and the server returns a JSON string of the corresponding structure, which is what is obtained.
One request arbitrary structure arbitrary data, convenient and flexible, do not need specialized interface or multiple requests.
Support additions and deletions, fuzzy search, remote function call and so on. can also remove duplicate data, save traffic to increase speed!
There is no interface for transmitting JSON data from this HTTP, and no documentation required!
The client no longer has to communicate with the server interface or documentation issues! Will never be a file of all kinds of error pits!
The server will no longer have to write new versions of the interface and documentation for compatibility with Legacy Clients! Will never be bored by the client anytime and anywhere!
Client:
Is this apijson so good? How do you do that?
Me:
Give me a chestnut (check out a list of friends like a circle):
Request:
{ "[]": { //Request an array "page": 0, //array condition "Count": 2, "user": { //Request query with table named User, return jsonobject "sex" named User: 0 //object condition }, "moment": { "[email protected]": "/user/id" ///default dependent path, starting from the path of the sibling object }, "comment[]": { //Request an array named Comment "page": 0, "Count ": 2, " Comment ": { " [email protected] ":" []/moment/id " //Full dependent path } }}}
Click here to test
Return:
{"[]": [{"User": {"id": 38710, "Sex": 0, "phone": "130003 8710 "," 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://stat ic.oschina.net/uploads/user/585/1170143_50.jpg?t=1390226446000 "]}," comment[] ": [{ "Comment": {"id": 4, "ParentID": 0, " Momentid ": 470," userId ": 310," Targetuserid ": 14604," C Ontent ":" 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", "t Argetusername ":" targetUserName-5904 "," UserName ":" userName-11679 "} }]}, {"User": {"id": 70793, "Sex": 0, "Phone": "1300070793", "name": "Name-70793", "Head": "HTTP://STATIC.OSCHINA.NET/UPLOADS/USER/1 174/2348263_50.png?t=1439773471000 "}," moment ": {" id ":", "" title ":" T itle-73 "," Content ":" This is a content...-73 "," userId ": 70793," picturelist ": ["http://my.oschina.net/img/portrait.gif?t=1451961935000 "]}," comment[] ": [{" Comment ": { "id": "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": +, "userId": 3, "Targetuserid": 62122, "content": "This is a content...-54", "Targetus Ername ":" targetUserName-62122 "," UserName ":" UserName-82381 "}} ] } ]}
Client:
It is clear at a glance, do not read the document AH!
I've been through a lot of documents. All, the document is more or less write a field, the field is wrong or multiple spaces, or the field type is wrong, do not know how much wasted debugging and communication time!
Sometimes the top with the app out of the question call us past, commissioning half a day only to find that the original service has changed the interface! And did not notify us in time!
Once the head of the tangle to change the single-layer comment to QQ that kind of multi-level comments, their own according to the previous interface to write a demo demo to the top, the top is satisfied with the decision to achieve the demand, the results of the back end and I have to discuss the interface to return the JSON structure, resulting in my side have to refactor the code,
Me:
With Apijson You can customize the JSON structure to return on demand, no interface, no documents, will not be the document pits, there will not be you say back-end Pat head fixed JSON structure caused by the client refactoring problem haha!
Client:
nice!
Service side:
Some interfaces need Currentuserid and Loginpassword, what are you doing?
Me:
Pass directly on the outermost layer, for example:
{ "Currentuserid": +, "Loginpassword": 1234, "User": { "id": 1 }}
Service side:
Where do you put the status code and the prompt information returned?
Me:
Also on the outermost layer, for example, the return result of the above request:
{ "status": $, "message": "Success", "User": { "id": "1", "sex": "0", "phone": "1234567890 ", " name ":" Tommy ", " head ":" http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000 " }}
Client:
One request arbitrary structure arbitrary data, convenient and flexible, do not need specialized interface or multiple requests?
I used to do an interface, the top half is the user's information, the lower part is his recent dynamic, up to 3, similar to the details.
I need to request two times separately:
User:
http://www.aaa.com/get/user?id=100
Moment list:
http://www.aaa.com/get/moment/list?page=0&count=3&userId=100
Is it possible to do this now:
User and Moment list:
http://www.aaa.com/get/{"User": {"id": [], "[]": {"page": 0, "Count": 3, "moment": {"userId": 100}}
Me:
Yes, that's it.
Client:
Good. How do you get rid of repetitive data?
Me:
such as QQ space, there is a dynamic list, each dynamic has the user and the corresponding dynamic content moment.
If you enter a person's space, it is his dynamic.
In the list data returned in the traditional way, each dynamic contains the same user, resulting in duplication of data:
Request:
http://www.aaa.com/get/moment/list?page=0&count=5&userId=100
Return:
{ "status": $, "message": "Success", "Data": [ { "id": 1, "content": "xxx1", ..., "User": { "id": +, "name": "Tommy", ... } , { "id": 2, " content": " Xxx2 ", ..., " User ": { " id ": +, " name ":" Tommy ", ... } , ... ]}
There are 5 duplicate user.
Instead of using Apijson, you can omit 4 duplicate User:
Request:
http://www.aaa.com/get/{"User": {"id": [], "[]": {"page": 0, "Count": 5, "moment": {"userId": 100}}
Return:
{ "status": $, "message": "Success", "User": { "id": +, "name": "Tommy", ... }, "[]": [ { "moment": {" id": 1, "content": "xxx1", ... } }, { " Moment ": { " id ": 2, " content ":" xxx2 ", ... } }, ... ]}
If you have previously obtained this user, you can also omit all duplicate User:
Request:
Http://www.aaa.com/get/{"[]": {"page": 0, "Count": 5, "moment": {"userId": 100}}
Return:
{ "status": $, "message": "Success", "[]": [ { "moment": { "id": 1, "content": "Xxx1", ... } }, {" moment": { "id": 2, "content": "xxx2", ...}} , ... ]}
Client:
The traditional way can also add a return format field to the interface, according to this field to decide whether to remove duplicate user Ah
Me:
Yes, but this can lead to the following issues:
1. Service side to add fields and to judge the field to return different data code.
2. The server should add the relevant instructions in the document.
3. This function is not necessarily used, because the client's UI requirements are often very easy to change, resulting in the lack of conditions to use this feature, in order to one or two versions to make the server and the client are not worth the toss.
The use of Apijson does not have these problems, because there is no need for interfaces or documents! and whether or not to look at the client's intention, the server does not have to do anything.
Client:
So, Praise!
Oh right, Apijson compared to the traditional way there is no missing function ah?
Me:
The traditional way can do apijson can do.
HTTP JSON interaction on the client and server side:
Client-Package Request-service side-Parse request-Generate response-client-parse response
The traditional way to request:
Base_url/lowercase_table_name?key0=value0&key1=value1 ...
Apijson Request:
Base_url/{tablename:{key0:value0, key1:value1 ...}}
TableName corresponding to the lowercase_table_name,key:value corresponding to Key=value, are strictly corresponding, so the traditional way request contains the information Apijson request can be included, The traditional way can realize the function Apijson certainly also can achieve.
Client:
Good
Service side:
How does Apijson ensure that the data returned by the server to different versions of clients is consistent?
For example, I last version of an interface return value is a, and now this version to all versions of the client return a+b, with the traditional method only need to service side to change the return value of the interface, the interface and the client do not have to change.
Using Apijson does not result in the return of a to some versions, some of which are a+b, so they cannot be unified?
Me:
Apijson the resolution and response of the request is done on the server side, which corresponds to project in Apijson.
The server can intercept the relevant request, such as request a value, the original return to a a+b to ensure that all versions of the client return a+b. There is no need for the client to change the code, as for the interface is even more unnecessary, because there is no interface.
Service side:
So I'm going to disagree? Returns different values for different versions of the client.
Me:
First of all, the demand is very small, such as reducing the price of movie tickets, you can not let the new client prices, the last version or the original price it?
There's a real need for this. You can also send a version number in the request by the client, and the server returns different values based on the version number.
Service side:
Yes, too. So how do you do permission handling with Apijson? Some of the data is for permissions to be manipulated. For example, login account requires login permissions, payment needs to pay permission.
Me:
After the server obtains the request from the client, a permission validation class is used before the corresponding table to verify that the operation permission is passed before the operation is allowed, otherwise an error message is returned.
The permission validation class can be this:
Package Zuo.biao.apijson.server.sql;import Java.rmi.accessexception;import Com.alibaba.fastjson.jsonobject;import zuo.biao.apijson.stringutil;/** Permission Validation class * @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"}; /** Verify that the permission is passed * @param request * @param tableName * @return */public static Boolean verify (Jsonobject re Quest, String TableName) throws Accessexception {try {Verify (Request, Getaccessid (tableName)); } catch (Accessexception e) {throw new AccessException (TAG + "Verify TableName =" + TableName + ", error =" + E.getmessage ()); } return true; /** Verify that the permission is passed * @param request * @param accessid can write access_login in the code directly, or build an Access table. Automatic processing of login password is implemented without writing code. * @return * @throws accessexception */public static Boolean verify (Jsonobject request, int accessid) throws A ccessexception {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_PASSW ORD)); if (Password.equals (stringutil.getstring (Getloginpassword (currentuserid)) = = False) { throw new Accessexception (TAG + "Verify Accessid =" + Accessid + ">> current UserId or Loginpassword Error "+" Currentuserid = "+ Currentuserid +", Loginpassword = "+ Pass Word); } Case Access_pay:password = stringutil.getstring (request.getstring (Key_pay_password)); if (Password.equals (stringutil.getstring (Getpaypassword (currentuserid)) = = False) {throw new accessexcept Ion (TAG + "Verify Accessid =" + Accessid + ">> Currentuserid or Paypassword error" + "Currentuserid =" + Currentuserid + ", Paypassword =" + password); } Default:return true; }}/** get permission 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; /** Get Login Password * @param userId * @return */public static String Getloginpassword (long userId) {// TODO queries and returns the login password of the corresponding userId return "123456";//Only Test with}/** get the payment password * @param userId * @return * * Public Static String Getpaypassword (long Currentuserid) {//TODO query and return the payment password of the corresponding UserID return "123456";//Test Only}}
Service side:
Well, it does. Just read the introduction of the project homepage, feel Apijson is really very powerful and convenient, even the interface and documentation are not written, and will not be in fitness or accompany the girlfriend to watch the movie suddenly received the client's phone.
But I have another problem, Apijson is dynamic splicing sql, is indeed flexible, but will not lead to SQL injection problem?
Me:
Apijson splicing SQL is done on the server side, the client cannot send SQL directly to the server. The entire database operation is fully controllable on the server side, the server can intercept the risk injection, the risk is not higher than the traditional way.
Service side:
That's my brother! I go to download try haha!
Client:
Haha, I also want to try, how to get the source code? Is it free?
Me:
It's open source on GitHub and is completely free.
Https://github.com/TommyLemon/APIJSON
Service side:
Very good! Has star!
Client:
Star +1, by the way also fork a research hey! In addition, the document is very detailed praise one!
Me:
What questions or suggestions can mention issue or send me e-mail [email protected], we exchange discussion ha!
Service side:
I feel I don't have to write a lot of interfaces, do not need to write compatible code, and do not need to write documents. Can focus on data processing, monitoring, statistics, analysis of haha!
Client:
I do not have to wait for the server to write a good interface to request, and now customize the return of the JSON, look at the request to know the return JSON structure, you can write the parse code directly haha!
(Note: The above is an adaptation of the real dialogue)
Apijson, let the interface and documentation go to hell!
source Code and documentation (remember to give a star Oh ^_^)
Https://github.com/TommyLemon/APIJSON
Download trial (test server address:39.108.143.172:8080)
apijsonclientapp.apk
"Turn from" https://www.cnblogs.com/LemonStantard/p/6157954.html
"Turn" Apijson, let the interface go to hell!