Using PeopleCode to Manage REST Service Operations

This section discusses how to:

  • Use PeopleCode to manage provider REST service operations.

  • Use PeopleCode to manage consumer REST service operations.

  • Generate fully-qualified URLs for REST resources.

This section discusses how to:

  • Read document template data and populate response messages.

  • Set HTTP response headers.

  • Retrieve HTTP response header data.

  • Set server-side caching.

Reading Document Template Data and Populating Response Messages

To read document template data and populate provider response messages, use the OnRequest method. You implement the OnRequest method using an application class, specifically using the IRequestHandler application interface.

When the OnRequest event is fired the document template is populated with the values based on the corresponding URI template. You can use the populated primitive values along with the URI Template index to determine the proper response message data to send back to the client. The code snippet below shows a simple example of reading the document template data and populating the response message. Note that one can override the HTTP return code that is sent as part of the response to the client.

import PS_PT:Integration:IRequestHandler;

class WeatherData implements PS_PT:Integration:IRequestHandler
   method WeatherData();
   method OnRequest(&MSG As Message) Returns Message;
   method OnError(&request As Message) Returns string;
end-class;

/* constructor */
method WeatherData
end-method;

method OnRequest
   /+ &MSG as Message +/
   /+ Returns Message +/
   /+ Extends/implements PS_PT:Integration:IRequestHandler.OnRequest +/
   /* Variable Declaration */
   
   Local Document &Doc;
   Local Compound &COM;
   Local Message &response;
   Local XmlDoc &weather_xmldoc;
   Local XmlNode &info, &country, &state, &city, &day, &data, &flightdata;
   Local Rowset &RS;
   
   /* get populated Document Template */
   &Doc = &MSG.GetURIDocument();
   &COM = &Doc.DocumentElement;
   
   &weather_xmldoc = CreateXmlDoc("");
   
 /* populate xmldoc with data from the Document Template */
   &info = &weather_xmldoc.CreateDocumentElement("WeatherInformation");
   &country = &info.AddElement("Country");
   &country.NodeValue = &COM.GetPropertyByName("country").Value;
   &state = &info.AddElement("State");
   &state.NodeValue = &COM.GetPropertyByName("state").Value;
   &city = &info.AddElement("City");
   &city.NodeValue = &COM.GetPropertyByName("city").Value;
   &day = &info.AddElement("Day");
   &day.NodeValue = &COM.GetPropertyByName("day").Value;
  
/*  determine HTTP method that was invoked to determine proper response 
/*  message */   
   If &MSG.HTTPMethod = %IntBroker_HTTP_GET Then
      
      &data = &info.AddElement("Forecast");
      &data.NodeValue = "55 degrees and raining";
      &response = CreateMessage(Operation.WEATHERSTATION_GET, 
        %IntBroker_Response);
      &response.SetXmlDoc(&weather_xmldoc);
      
   End-If;
   
   If &MSG.HTTPMethod = %IntBroker_HTTP_DELETE Then
      
      &data = &info.AddElement("Forecast");
      &data.NodeValue = "deleted";    
      &response = CreateMessage(Operation.WEATHERSTATION_DELETE, 
        %IntBroker_Response);
      &response.SetXmlDoc(&weather_xmldoc);
      
   End-If;
   
   Return &response;  
end-method;

method OnError
   /+ &request as Message +/
   /+ Returns String +/
   /+ Extends/implements PS_PT:Integration:IRequestHandler.OnError +/
   Local Message &Fault_Msg;
   Local Document &fault_doc;
   Local Compound &COM;
   
   If &request.HTTPMethod = %IntBroker_HTTP_GET Then
      
      &Fault_Msg = CreateMessage(Operation.WEATHERSTATION_GET, 
        %IntBroker_Fault);
      &fault_doc = &Fault_Msg.GetDocument();
      
      &COM = &fault_doc.DocumentElement;
      &COM.GetPropertyByName("fault_data").Value = &request.IBException.
        ToString();
      
      Return &fault_doc.GenXmlString();
   End-If;
   
   Return "";
   
end-method;

Setting HTTP Reponse Headers

Use the LoadRESTHeaders method of the IBInfo class to load the response headers defined on the routing for a REST-based service operation. Once loaded, the headers can be modified without specifying the connector override property.

The code snippet below shows how to add HTTP response headers to the any REST based service operation response within the OnRequest event.


&response = CreateMessage(Operation.WEATHERSTATION_GET, %IntBroker_Response);
 
&bRet =   &response.IBInfo.LoadRESTHeaders();  

/* any/ modify additional Headers not defined on Routing */
&bRet = &response.IBInfo.IBConnectorInfo.AddConnectorProperties
    ("Content-Language ", "eng ", %HttpHeader);
  
Return &response;

Retrieving Response HTTP Header Data

You can use the REST method type Head to retrieve meta-information written in response HTTP headers, without having to transport the entire content.

The REST-based service operation created with a method of HEAD does not have a request or response message.

You can assign the OnRequest handler used for the GET method to the service operation to check if the method type is HEAD and, if so, simply send back the HTTP response headers.

The following code snippet shows how to use the OnRequest method to retrieve HTTP response headers

Note: HTTP response headers can be sent back to the client for all REST method types.

If &MSG.HTTPMethod = %IntBroker_HTTP_HEAD Then

&response = CreateMessage(Operation.WEATHERSTATION_HEAD, 
  %IntBroker_Response);
 
&bRet =   &response.IBInfo.LoadRESTHeaders();  

/* any additional Headers not defined on Routing */
&bRet = &response.IBInfo.IBConnectorInfo.AddConnectorProperties
 ("Content-Language ","eng ", %HttpHeader);

&bRet = &response.IBInfo.IBConnectorInfo.AddConnectorProperties
 ("WWW-Authenticate", "Basic",  %HttpHeader);
  
Return &response;
End-If;

Setting Server-Side Caching

For provider REST GET service operations you can set server-side caching by setting the SetRESTCache method on the Message object in the OnRequest PeopleCode event. The SetRESTCache method takes a future Date Time object.

If you set server-side caching the system caches the entire transactional data for the specific URI resource. Subsequent requests from a client with an identical resource will result in the data being pulled from memory/file cache.

At any time you can delete the cache by calling the DeleteRESTCache method on the IntBroker PeopleCode object. The DeleteRESTCache method takes the service operation and service operation version as input variables.

This section discusses how to:

  • Invoke a consumer REST service operation.

  • Add REST HTTP connector headers.

Invoking a Consumer REST Service Operations

To invoke a consumer REST service operation, the message is instantiated and then the document template is retrieved and populated. The URI index is selected and a SyncRequest method is invoked. The response message contains the HTTP return code. Processing of the data is the same as any other SyncRequest method. In the case of an error, if the User Exception option is selected on the routing, you can attempt to read the fault if defined on the service operation. If the HTTP response code is the same as that defined on the fault message, then the fault message is created and returned. You can read the fault in the document, if the fault message is a Document message type. The message property IsFault is read to determine if a fault message was created.

The code example shows a simple example of populating the document template data and entering the URI resource index to use and invoking the SyncRequest method.

The GetURIDocument method of the Message class is used to retrieve the URI for the REST based on the specified index. The URIResourceIndex property of the Message class is used to set or return the index for the URI as an integer. This index corresponds to the row number in the URI grid of the REST Resource Definition section of the service operation definition.

Declare Function out_BI_results PeopleCode QE_FLIGHTDATA.QE_ACNUMBER 
  FieldFormula;
	
&MSG = CreateMessage(Operation.MAPS_GET);

/* Get URI Document and populate with data */
&DOC = &MSG.GetURIDocument();

&COM = &DOC.DocumentElement;

&COM.GetPropertyByName("MapType").Value = "topographic";
&COM.GetPropertyByName("Scale").Value = "1:63";
&COM.GetPropertyByName("Planet").Value = "Earth";
&COM.GetPropertyByName("Country").Value = "USA";
&COM.GetPropertyByName("City").Value = "WhiteSalmon";
&COM.GetPropertyByName("Name").Value = "MainSteet";

/* Set URI Resource Index to be used */
&MSG.URIResourceIndex = 1;
&return_message = %IntBroker.SyncRequest(&MSG);

/* Get return data and display */

If &return_message.ResponseStatus = %IB_Status_Success Then
   
   &xmldocReturn = &return_mesage.GetXmlDoc();
   out_BI_results(&xmldocReturn.GenXmlString());
 
/* Read Response Headers if set */
   For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfConnectorProperties()
      
     If &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesType(&i) = 
       %HttpHeader
   
     Then
         
       &name = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesName(&i);
       &value = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesValue(&i);
     End-If;
      
   End-For;
  
Else
   
   If &return_message.IsFault = True Then
      
      &Fault_Doc = &return_message.GetDocument();
      &COM = &Fault_Doc.DocumentElement;
      out_BI_results(&COM.GetPropertyByName("fault_data").Value);
      
   Else
      out_BI_results(&return_message.IBException.ToString());
   End-If;
   
End-If;

Adding REST HTTP Connector Headers

Use the LoadRESTHeader method of the Message class to add HTTP header properties not defined on the routing for the service operation.

The code snippet below shows how to modify HTTP headers using PeopleCode

Note: The connector override flag in PeopleCode does not need to be set in this case.

No HTTP properties are currently applicable for REST and will be removed by the Integration Broker framework.

&request = CreateMessage(Operation.MAPS_GET);
 
&bRet = &request.LoadRESTHeaders();  

/* add any additional Headers not defined on Routing */     
&bRet = &request.IBInfo.IBConnectorInfo.AddConnectorProperties
  ("Content-Language ", "eng ", %HttpHeader);

In most REST-based services, representations are hypermedia documents that contain not just data, but links to other resources.

Use the GetUrl method contained in the %IntBroker class to generate fully-qualified URLs for REST service operation resources. You can use the URLs with defined HTML definitions to dynamically add REST-based web service URL links.

Note: A provider or a consumer REST based service operation representation can be used to generate the fully-qualified link(s).

The syntax of the GetUrl method is:

string &str = %IntBroker.GetURL( string <Service Operation>, integer 
<Resource Index of Service Operation>,  document <Document object 
defined for document Template> , <optional> bool <secure/ unsecure 
REST tgt location>, <optional> bool <add encoding for unsafe characters >

The following example shows within an implementation (OnRequest event) of a REST-based provider service, HTML is generated using links defined from other REST-based service operations.

method OnRequest 

 Local Document &Doc_Tmpl, &DOC;
 Local Compound &COM_Tmpl, &COM;
 Local Message &response;
 Local string &STR, &STR1, &STR2, &STR3, &STR4, &strHTML;
 Local boolean &bRet;
   
 &response = CreateMessage(Operation.WEATHERSTATION_GET, %IntBroker_Response);

 /* read URI Document to get parms out from the request*/
 &Doc_Tmpl = &MSG.GetURIDocument();
 &COM_Tmpl = &Doc_Tmpl.DocumentElement;
 
 /* Instantiate a Document object based on the REST based Service */  
 /* Operations Document Template for which to create a link.      */

 &DOC = CreateDocument("Weather", "WeatherTemplate", "v1");
 &COM = &DOC.DocumentElement;

 /* based off the data from the request populate the Document object */
   
   If &COM_Tmpl.GetPropertyByName("state").Value = "Washington" Then
      
      &COM.GetPropertyByName("state").Value = "Washington";

      /* call new method to create fully qualified URL(s) */

      &COM.GetPropertyByName("city").Value = "WhiteSalmon";
      &STR = %IntBroker.GetURL("WEATHERSTATION_GET", 2, &DOC);
      
      &COM.GetPropertyByName("city").Value = "Troutlake";
      &STR1 = %IntBroker.GetURL("WEATHERSTATION_GET", 2, &DOC);
      
      &COM.GetPropertyByName("city").Value = "Yakima";
      &STR2 = %IntBroker.GetURL("WEATHERSTATION_GET", 2, &DOC);
      
      &COM.GetPropertyByName("city").Value = "Lyle";
      &STR3 = %IntBroker.GetURL("WEATHERSTATION_GET", 2, &DOC);
 
      /* use these URLs as bind variables for the HTML definition */     
      &strHTML = GetHTMLText(HTML.WEATHER_CITIES, &STR, &STR1, &STR2, &STR3);

      /* set the data in the response message */
      &bRet = &response.SetContentString(&strHTML);
      
   End-If;

Return &response;
end-method;