Whenever someone creates API RPG program, he is faced with problem how to correctly build response. In this article I will try to give some tips how to do it. First of all, the main tip is to split problem into small problems. Each project (task) can be divided to very small atomic API-s. Developer should avoid to create very complex responses. The simple programs (microservices) will be easier to maintain and will contain less bugs. The best idea is to not mix types of response in one program. For example itemPrices.get method should return array of prices. Or itemBatch.get should return simple object which will contain only one batch for given item. But what should return salesOrder.get program? Should it return only header information? Or should it return header information together with lines? Should we add also order header texts to the returned information? The answer is….. it depends. The best idea is to split this problem into several API-s. Each responsible for one particular object:
Then the client can combine full information by calling number of API-s one after another. This kind of programing (microservices) is the most effective and the most reusable. But sometimes it is really required to get everything in one go salesOrder.get should return everything about sales order (header, lines, texts, discounts etc…). Now is time to understand differences between “JSON” and “Old” and “New” aperïo protocols. JSON is just format of data which is used to transfer information between Dispatcher and Aperïo RPG program. Whenever You create RPG program you shouldn’t think about JSON. Better is to think about response. What belongs to what? Not focus much, how will it be represented in JSON. That is why in aperïo we have procedures which don’t even mention JSON: respAddElement or respAddStringField. First You create element of response…. then add some fields to it. The “Old” protocol of aperïo states that when You create simple object response You need to put everything to element “data”. When You would like to create table (array) response then everything should be put into element named “items” which is put into “data”.
Old protocol, simple object response
{
"data":{"field1":"value1", "field2":"value2"}
}
Old protocol, array response
{
"data":{
"items":[
{"field1":"value1", "field2":"value2"},
{"field1":"value1", "field2":"value2"}
]
}
}
The “Old” request and response require to put into JSON two additional elements which represents the protocol. {“IptorAPI”:“1.0”,…,“id”:“jx1k6dl2”}
The “New” request and response differ from “Old” protocol by not adding “IptorAPI” and “id”. If there is no “IptorAPI” in the request then the aperïo creates REST-full ready response. Then everything is put into “data” element. It is much easier and faster to pass this response as REST-full by dispatcher. The dispatcher do not need to parse the response from RPG program but just substring “data” object from RPG response and pass it as web service response.
New protocol, simple object response
{
"data":{"field1":"value1", "field2":"value2"}
}
New protocol, array response
{
"data":[
{"field1":"value1", "field2":"value2"},
{"field1":"value1", "field2":"value2"}
]
}
Notice that in new protocol “data” can be either object {} or array []. This is very important difference compare to “Old” protocol. In “Old” protocol the data was always object and it was possible to set it structure to “object” by default even if programmer forgot to establish it. Now the programmers must be more precise. Whenever You add to Your code:
respAddElement('data');
Aperïo do not know if the element of response “data” will it have structure of “object” (simple element) or “array”. By default, aperïo set structure of “data” element to “object” (means simple object). What happen if You repeat the same command in Your program?
respAddElement('data');
This time aperïo “thinks” that You want to add another row to the response and changes structure of element “data” to “array”. In most cases the default behavior of aperïo is correct. But programmer must know how to explicitly set the structure of response elements. The respAddElement() procedure supports 3 parameters:
Parameter | Type | Description | |
---|---|---|---|
element | 30A VARYING, VARSIZE | Mandatory | Name of element |
parent | 30A VARYING, VARSIZE | Optional, can be omitted | Name of parent element. This parameter points parent for currently added element. When You want to send response with subfile (array) The recommendation is to use sub element name “items”. |
structure | 10A VARYING, VARSIZE | Optional, can be omitted | Structure of element (“array” or “object”) |
So, developer can explicitly say what is the structure of element. Note: “data” element has no parent so You can pass blank string or *omit parent parameter:
//for simple (object) structure of data
respAddElement('data': '': 'object');
//or
respAddElement('data': *omit: 'object');
//for array structure of data
respAddElement('data': '': 'array');
//or
respAddElement('data': *omit: 'array');
Example of program which will create simple object as response:
respAddElement('data': *omit: 'object');
respAffStringField('data': 'myField1': 'ABC');
respAffStringField('data': 'myField2': 'DEF');
respAffNumericField('data': 'myField3': 123);
respAffNumericField('data': 'myField4': 456);
the response will look as follows:
{
"data":{"myField1":"ABC","myField2":"DEF","myField3":123,"myField4":456}
}
Example of program which will create array as response. Let imagine FILE contains following data:
FLD01 | FLD02 | FLD03 | FLD04 |
---|---|---|---|
AAA | BBB | 111 | 222 |
CCC | DDD | 333 | 444 |
EEE | FFF | 555 | 666 |
setll *start FILE;
read FILE;
dow %EOF(FILE);
respAddElement('data': *omit: 'array');
respAffStringField('data': 'myField1': FLD01);
respAffStringField('data': 'myField2': FLD02);
respAffNumericField('data': 'myField3': FLD03);
respAffNumericField('data': 'myField4': FLD04);
read FILE;
enddo;
//the response will look as follows:
{
"data":[
{"myField1":"AAA","myField2":"BBB","myField3":111,"myField4":222},
{"myField1":"CCC","myField2":"DDD","myField3":333,"myField4":444},
{"myField1":"EEE","myField2":"FFF","myField3":555,"myField4":666}
]
}