A structure is, in functional terms, a named list of fields that correspond to data with specific format characteristics. For example, a structure called "CustomerDetails" could have the following fields:
•Customer ID •Surname •First Name •Address •Country •Email address In technical terms, a structure is a helpful instrument for mapping output columns and host variables of a SQL statement executed by a REST method to formatting on the client side (that is, on the side of the caller of the service).
The easiest way to create a structure is to have it derived from a SQL statement as part of generating a method implementation from SQL. You can also derive a structure from a SQL statement or from a table definition as a separate action.
Finally, it is also possible to create a structure by defining all its aspects manually in the Structures window or tab. To do this, choose Define, Structures from the menu.
|
Structures in USoft Service Definer are used to easily consume and produce, in a REST service, both JSON and XML data formats. You can use the same structure to generate JSON or XML or both.
Accepts attribute
If a structure is specified as input parameter of a REST method, you can have the runtime Services Framework convert the XML or JSON format of the posted input data to fields in the structure. Do this by specifying, in Service Definer, one of the following media types as the value of the Accepts attribute of the method:
Accepts attribute
|
text/xml
|
XML request messages are accepted
|
application/json
|
JSON request messages are accepted
|
text/xml;application/json
|
Both XML and JSON request messages are accepted
|
At runtime, the client specifies the actual format of the request message by setting the Content-Type HTTP header.
The Accepts attribute must be empty if the HTTP verb is GET. The default value for the Accepts attribute is 'text/xml'.
Produces attribute
Likewise, if a structure is specified as return parameter of a REST method, you can have the runtime Services Platform pass the return data produced by the method as either XML or JSON. Do this by specifying, in Service Definer, one of the following media types as the value of the Produces attribute of the method:
Produces attribute
|
text/xml
|
XML response messages are accepted
|
application/json
|
JSON response messages are accepted
|
text/xml;application/json
|
Both XML and JSON response messages are accepted
|
At runtime, the client specifies the actual format of the reponse message by setting the Accept HTTP header.
The default value for the Produces attribute is 'text/xml'.
|
Structures in USoft Service Definer are also used to easily get or set the output or input of a SQL statement.
At runtime, USoft will automatically fill the fields of a structure with the output of a SELECT statement if the field specifies a mapping to a output column in the SQL Statement. The mapping may be specified as Annotation of a field, using the syntax @Column(name="<label name>").
Example
@Column(name="RES_ID") indicates that a field corresponds to an output column of a SQL Statement that has RES_ID as its column name or alias name.
|
If a structure is specified as input parameter of a REST method, you can have the runtime Services Framework automatically setting host variables in a SQL Statement to incoming data values. Do this by setting the Annotation attribute of the field using the syntax @Column(name="<host variable name>").
In this scenario,you do not need to create structures by manual coding. The necessary structures are automatically created when you generate a REST method from the SQL statement. In the SQL statement, the name of the structure is used in the host variable. The syntax is :<structure name>.<field name>.
Example
In this SQL statement, the name of the structure is 'MyPersonNameStructure':
UPDATE person
SET
(
first_name
, family_name
) =
(
SELECT :MyPersonNameStructure.FirstName
, :MyPersonNameStructure.SurName
)
WHERE person_id = :id
|
The input parameter ':id' in the WHERE clause is of a different type than the host variables in the SET clause. This input parameter is passed at runtime as part of the request URL of the REST service.
In this example, the structure is used as follows in the Implementation of the method:
Integer result = (Integer)sql( "UPDATE_PERSON" , new Object[]{ objMyPersonNameStructure, id } );
|
where UPDATE_PERSON is the name of the SQL statement.
|
If the output of a SQL statement has multiple rows you can use arrays of structures to receive all rows. The syntax is: MyReservationStructure[], where MyReservationStructure is the name of the structure. For example, you can write as the Implementation of a method:
MyReservationStructure[] reservations = ( MyReservationStructure[])sql( MyReservationStructure[].class, "GET_CURRENT_BOOKINGS" );
|
If the output or input of a REST Service contains has a list of elements held in an XML or JSON array, you can use the same syntax MyReservationStructure[] in the Type field of the Parameter. Such a list of elements could look like this in XML:
<MyReservationStructures>
<MyReservationStructure participants="1" id="160">
<destination>AUSTRALIA</destination>
<tour>53</tour>
<type>ISLAND SUNTANNER</type>
</MyReservationStructure>
<MyReservationStructure participants="3" id="157">
<destination>AUSTRALIA</destination>
<tour>54</tour>
<type>ISLAND SUNTANNER</type>
</MyReservationStructure>
<MyReservationStructure participants="1" id="182">
<destination>BRAZIL</destination>
<tour>144</tour>
<type>RAINFOREST RIDE</type>
</MyReservationStructure>
</MyReservationStructures>
|
Or it could look like this in JSON:
[
{
"participants": 1,
"id": 160,
"destination": "AUSTRALIA",
"tour": 53,
"type": "ISLAND SUNTANNER"
},
{
"participants": 3,
"id": 157,
"destination": "AUSTRALIA",
"tour": 54,
"type": "ISLAND SUNTANNER"
},
{
"participants": 1,
"id": 182,
"destination": "BRAZIL",
"tour": 144,
"type": "RAINFOREST RIDE"
}
]
|
|
Using annotations, you can map data in incoming and outgoing XML messages variously to XML elements or to XML attributes:
•To specify that a field of a structure maps to an element in the XML structure, specify @XmlElement(name="<xml element name>") as Annotation for the field. •To specify that a field of a structure maps to an attribute in the XML structure, specify @XmlAttribute(name="<attribute name>") as Annotation for the field. Example
You have a REST service that produces the following XML response message on the basis of a structure named MyPersonStructure:
<MyPersonStructure>
<PERSON_ID>137</PERSON_ID>
<FIRST_NAME>Johnny</FIRST_NAME>
<FAMILY_NAME>LOGAN</FAMILY_NAME>
</MyPersonStructure>
|
You want this output to look like this:
<Client ID="137">
<FirstName>Johnny</FirstName>
<Surname>LOGAN</Surname>
</Client>
|
To achieve this, follow these steps:
1. | Change the annotation for the structure from @Entity;@XmlRootElement(name="MyPersonStructure") to: |
@Entity;@XmlRootElement(name="Client")
2. | Change the annotation for the PERSON_ID field from @Column(name="PERSON_ID");@XmlElement(name="PERSON_ID") to: |
@Column(name="PERSON_ID");@XmlAttribute(name="ID")
| Note in particular that @XmlElement was replaced by @XmlAttribute. |
3. | Change the annotation for the FIRST_NAME field from @Column(name="FIRST_NAME");@XmlElement(name="FIRST_NAME") to: |
@Column(name="FIRST_NAME");@XmlElement(name="FirstName")
4. | Change the annotation for the FAMILY_NAME field from @Column(name="FAMILY_NAME");@XmlElement(name="FAMILY_NAME") to: |
@Column(name="FAMILY_NAME");@XmlElement(name="Surname")
|
In the Implementation code of a method, you can access data from a structure, for example (for a structure named "MyBookingStructure"):
Reservation reservation = (Reservation)sql(
Reservation.class, "MyBookingStructure", new Object[]{ id }
);
|
and then use that data in a subsequent sql() function in that same Implementation code, for example:
CountryHighlights[] highlights = (CountryHighlights[])sql(
CountryHighlights[].class, "GET_COUNTRY_HIGHLIGHTS", new Object[]{ reservation.destination }
);
|
|
See also
USoft Service Definer Objects
Annotations
Deriving structures from SQL statements or tables
|