Whether you design a native phone app or a "face-changing Application" (a multiple-page Web application without a page refresh) mentioned earlier in the article, you need back-end application servers to provide business support. So, how to design the backend service interface is one thing that must be considered before developing.
Talking about interface design, we need to consider from two dimensions: protocol (PROTOCOL) and prototype (Prototype), short 2P dimension.
A prototype defines an abstract form of a call. Suppose to do door-to-door delivery business, each "merchant" is an object, named "Store", then a "Query Merchant List" interface, you can design its prototype:
Store.query ()-> tbl (ID, name, DSCR)
In the prototype, the call named Store.query is described, the parameter is null, and the data returned by the table type represents a table (described below), each row in the table has a list of IDs and names, and a few columns representing the properties of a merchant object.
Next, you need to design a protocol to implement it. You can do this by using the HTTP protocol for the client's request to the server, the HTTP GET or POST method, placing the call name at the end of the URL, placing the parameter in the URL parameter (not here), and the server-side return data is described in JSON format. As a result, the client needs to send an HTTP request like this:
Get/api/store.query
This is the service interface design of the somersault cloud framework. In fact, loop cloud framework is the implementation of the DACA architecture, DACA full name "distributed access and control framework", which has defined the client-server how to communicate, that is, the design of the above example further standardize, known as the BQP Protocol (Business Query Protocol); DACA also defines how the client invokes the service interface , called the client-side public invocation interface, as described in the CALLSVR call below.
The design style of BQP protocol is between restful and RPC, so it is called REST-RPC style. Leonard Richardson and Sam Ruby introduced the terminology REST-RPC hybrid architecture (Chinese translation) in their book RESTful Web Services, which does not use the extra envelope format to wrap the invocation name and parameters like soap or XML-RPC , instead of transferring the data directly over HTTP, which is similar to a REST-style Web service, it does not manipulate resources in such a way as standard HTTP put/delete, and stores the invocation name in the URI (in the case of Store.query).
We examine the main principles of protocol design are: clear and easy to realize the transmission and high processing efficiency
In contrast to these principles, the restful style is clear and understandable, but the compatibility of methods such as HTTP Put/delete is not good, regardless of the server or client encountered obstacles in implementation, and RPC-style design, not only a lot of readability, and packet unpack less efficient. Therefore, from a practical point of view, somersault cloud design thought that REST-RPC is a better choice at present.
In the BQP protocol, the business interface is divided into function call interfaces (such as login calls) and object invocation interfaces (such as Store.query calls). The function invocation interface is free to design prototypes, and the object invocation interface is actually a special function call, which is used to manipulate business objects and have relatively fixed prototypes that the designer can cut or extend. The main difference between the two types of interfaces in communication protocol and client usage is that the implementation model of backend service is different.
This article only discusses object invocation interfaces. The BQP protocol defines five standard operations for an object: query lists (queries), getting details (get), adding (add), updating (set), and Deleting (DEL). The following details are given in detail, and we first assume the object of the "merchant" (Store), whose data model is described as follows:
@Store: ID, Name, addr, tel, dscr
This represents the Merchant table store, with fields such as ID, name, and so on. Note: The DACA specification suggests that the ID should be used as the primary key when designing the data model.
The DACA specification requires the client to provide a Callsvr method to invoke the service interface, which, in the front of the loop cloud, is a JS function, and its prototype is
Callsvr (AC, param, FN, Postparam, useroptions?)-> XMLHttpRequest
or
callsvr (AC, FN, Postparam?, Useroptions?) -> XMLHttpRequest
Where AC represents the invocation name (action), Param and Postparam are arguments passed by URL and post content, respectively, if there is no param, the argument (i.e. the second prototype) can be ignored. FN is the callback function, called FN (data), where parameter data is the returned JSON object, and the return value description in the type reference interface prototype.
A parameter with a question mark indicates that it can be defaulted.
function returns the XMLHttpRequest object, which is the same as the $.ajax return value in jquery.
The above call is asynchronous, that is, the function ends immediately after execution, and the service-side data is returned to the callback function, FN. You can also make a synchronous call, as long as you change the function name Callsvr to Callsvrsync, which means that it will return the data to the server end, and that the return value is no longer a XMLHttpRequest object, but a JSON object returned by the service interface. When we test the interface in the Chrome console window, we use synchronous calls to make it easier to see the results.
As long as you are familiar with these client interfaces, you can invoke any interface based on the interface prototypes in the design document without further understanding of the BQP underlying protocol details. adding Objects
The prototype in the BQP protocol that defines an object addition operation is as follows:
{Object}.add () (POST fields ...)-> ID
Generally in the prototype definition, the parameter part is only a bracket, which means that the parameter can be passed by URL or post content. The two parentheses appear here, which means that the URL parameter and the post parameter are not mixed, and that the two parentheses represent the URL and post parameters in turn.
In this way, we add a merchant that can be used:
var Postparam = {name: "Hua Ying Snack", Addr: "Silver Branch Road 88th", Tel: "13712345678"};
Callsvr ("Store.add", Api_storeadd, Postparam);
function Api_storeadd (data) {
///According to the return value in the prototype definition, data is the ID value.
alert ("id=" + data);
}
Because there is no URL parameter, the second argument of Callsvr can be omitted. If you want to write a complete, it would be like this:
Callsvr ("Store.add", NULL, Api_storeadd, Postparam);
If the call succeeds, the specified callback function is invoked, and if the call fails, the front-end framework takes over the error handling, which the caller generally does not care about. Update Objects
The prototype is:
{Object}.set (ID) (POST fields ...)
The return value is not specified, indicating that there is no specific return value when the call succeeds. The back end of the somersault cloud returns the string "OK".
If you want to update the id=8 this merchant's corresponding contact number:
var param = {Id:8};
var Postparam = {Tel: "13812345678"};
Callsvr ("Store.set", Param, Api_storeset, postparam);
function Api_storeset (data)
{
alert ("Update succeeded");
}
Note: The fields to be updated must be placed in the post parameters.
Empty a field
In the BQP protocol, setting a field to an empty string is generally ignored by the server, but in a set operation, if a field is set to be empty (or a specific string "null") in Postparam, the field is emptied.
To empty a merchant's address:
var Postparam = {addr: ""};
or var Postparam = {addr: "null"};
Callsvr ("Store.set", {id:8}, Api_storeset, Postparam);
The next time you get the merchant with Store.get, the Visible property addr value is null (Note: Not the field string "null") deletes the object
The prototype is:
{Object}.del (ID)
The call is simple, if you want to delete the id=8 corresponding merchant:
Callsvr ("Store.del", {Id:8}, function (data) {
alert ("Delete succeeded");
});
Get Object Details
The prototype is:
{Object}.get (ID, res?)-> {fields ...}
The default return object corresponds to the field in the primary table, and can also be designed to add child objects or virtual fields to the returned content (the implementation method references the back-end document of the Somersault cloud).
Suppose that when you design the Get merchant interface, you add a child object named items, which is designed with the interface prototype:
Store.get (ID, res?)-> {ID, name, addr, tel, @items =[item]}
Item:: {ID, name, price}
(Note: In the design of interface prototypes, the "Cocoon representation" layer to parse and describe the object type, not in the scope of this article, see related articles.) )
According to the interface, to obtain details of a merchant can be called this way:
Callsvr ("Store.get", {id:8}, api_storeget);
function Api_storeget (data) {...}
Return data like this:
{
id:8,
name: "Hua Ying Snack",
addr: "Silver Branch Road 88th",
Tel: "13812345678",
items: [
{id:1001, Name: "Meat small Cage", price:10.0},
{id:1002, Name: "Meat dumpling", price:8.0}
...
]
}
Optional parameter res in the URL it represents "result", that is, the list of fields to be returned, separated by commas in the middle of multiple fields. If you do not want to return to the default field, you can specify which fields you want through this parameter.
To obtain details of the merchant, return only the name and telephone number of the shop:
Callsvr ("Store.get", {id:8, res: "Name,tel"}, Api_storeget);
function Api_storeget (data)
{
//Data example: {name: "Hua Ying Snack", Tel: "13812345678"}
Query Object list
Query operations are the most flexible and complex of standard operations, with many optional parameters, with two prototypes (the format of the returned content is different):
{Object}.query (res, cond, by, by, Distinct?=0, _pagesz?=20, _pagekey, _fmt?)-> tbl (field1,field2,...)
{object}.query (Wantarray=1, ...)-> [{field1,field2,...}]
The first prototype returns a special table type (described below, can be turned into an object array, which is good for data refinement and supports paging; the second prototype has more Wantarray parameter settings (other parameter usages are the same), the return type becomes an array of objects, supports child objects, but it does not support paging operations, Less commonly used. Table Type
If no parameter Wantarray (the first prototype) is specified, the returned content is the table type, which cannot return child objects (such as the child Objects list items in the previous get operation), such as a merchant list:
Callsvr ("Store.query", api_storequery);
function Api_storequery (data) {...}
The format of the data parameter in the callback function Api_storequery is:
{
h: ["id", "name", "Addr", "tel"]
d: [
8, "Hua Ying Snacks", "Silver Branch Road 88th", "13812345678"],
[9, ...]
...
]
nextkey:998
}
Where property H is the column array group, d represents the data row array, and the value array for each row corresponds to element one by one in the column array group.
If there is a property nextkey, it means that this is only part of the data, to take down a page of data, you can use the same query, with the parameters _pagekey set to this value, such as
Callsvr ("Store.query", {_pagekey:998});
This table structure design is advantageous to the transmission efficiency enhancement, simultaneously facilitates the paging mechanism the design.
The Loop cloud Front-End provides function Rs2array, which converts this data to an array of commonly used objects:
var arr = rs2array (data);
Get the arr like this:
[
{id:8, Name: "Hua Ying Snack", Addr: "Silver Branch Road 88th", Tel: "13812345678"},
{id:9, ...}
...
]
Query Parameters
Object queries Support flexible query conditions (via parameter cond-condition), sort methods (parameters by order), and return fields (parameter res, as with get operations).
If you understand SQL statements, you'll find these parameters simple to use. Parameter res Specifies the return field, with multiple fields separated by commas, for example, res= "Field1,field2". Parameter cond Specifies the query condition whose syntax resembles the "WHERE" clause of the SQL statement, such as "field1>100 and field2= ' Hello '", and note that string values are enclosed in single quotes. Parameter by specifies the sort criteria that can be used to refer to the ORDER BY clause of the SQL statement, for example: orderby= "id desc", or multiple fields sorted: "TM Desc,status" (inverted by time, and then in the state)
For example, to query for any merchant whose ID is less than 10 and whose name begins with "Hua Ying", the return result is sorted by first name:
var cond = "id<10 and name like ' Hua Ying '";
var param = {res: "id,name,addr", Cond:cond, by: "Name"};
Callsvr ("Store.query", Param, api_storequery);
function Api_storequery (data)
{
///Rs2array The table type to the object array
var arr = rs2array (data);
Traverse each merchant
Arr.foreach (function (store) {
//Because the res parameter is specified, the store object type is: {ID, name, addr}}
);
Although these parameter values are similar to SQL statements, they have some security restrictions: res, by which only a list of fields (or virtual fields) cannot appear, such as functions, subqueries, and so on. Cond can be combined with and or or by multiple conditions, and the left side of each condition is the field name, and the right is a constant. Operations on fields are not allowed, subqueries are not allowed (there can be no keywords such as select).
The following conditions are not allowed in the image parameter cond:
Left (type, 1) = ' A ' --only field on the left-hand side of the condition, no calculation or function
type=type2 allowed --field comparison with field does not allow
type in (select type from table2) --The child table does not allow
Paging Support
Parameters _pagesz and _pagekey are used to support paging. _PAGESZ specifies how many data to return each time (20 is returned by default).
Here is an example of getting all the merchants. First time query:
Callsvr ("Store.query")
Return data like this:
{nextkey:10800910, H: [ID, ...], d: [...]}
The nextkey indicates that the data has not been returned and the _pagekey field needs to be filled in to query the next page.
Second query (next page):
Callsvr ("Store.query", {_pagekey=10800910});
Return:
{nextkey:10800931, H: [...], d: [...]}
Still return nextkey field description You can also continue with the query, and then query the next page:
Callsvr ("Store.query", {_pagekey=10800931});
Return:
{h: [...], d: [...]}
Returns the data without the Nextkey attribute, indicating that all data has been fetched.
If you want to return the total number of records at the first query, you can set _pagekey=0:
Callsvr ("Store.query", {_pagekey:0})
This will return
{nextkey:10800910, total:51, H: [ID, ...], d: [...]}
A multiple total field represents the sum of records. Because the default page size is 20, you can expect a total of 51/20=3 pages. Object List Export
Setting the parameter _fmt in the object query interface, you can output the specified format, which is typically used to export the list to a file. The parameters support the following values: CSV: comma-delimited UTF8 encoded text txt: tab-delimited UTF8 text Excel: Similar to CSV, but GB2312 encoded in Chinese so that Ms Excel, which does not support UTF8 encoding, can be opened directly.
Note that because there are pagination by default, to export all data, you typically specify a large page size, such as _pagesz=9999.
For example, to export a merchant list, you can write this:
var url = makeurl ("Store.query", {_fmt: "Excel", _pagesz:9999});
location.href = URL; Downloading Excel files
Note: Be sure to use the function provided by the framework Makeurl to generate URLs, not handwritten URLs. Its usage is similar to that of CALLSVR, with incoming call name AC and URL parameter param.