Chris Malek is a PeopleTools® Technical Consultant with two decades of experience working on PeopleSoft enterprise software projects. He is available for consulting engagements.
About Chris Work with ChrisIntroducing a small but powerful PeopleSoft bolt-on that makes web services very easy. If you have a SQL statement, you can turn that into a web service in PeopleSoft in a few minutes.
In this article we will create a simple REST GET service in PeopleSoft using PeopleTools greater than 8.55. It will have the following characteristics.
This example is similar to the Synchronous Example. However, in that example we were posting to the HttpListeningConnector
endpoint. The HttpListeningConnector
accepts everything as an HTTP POST method. In REST, you use different HTTP verbs/methods to describe what your intended operation is. In this example, we will be “getting” data from PeopleSoft (sort of) so we will be using an HTTP GET
method.
The steps required to create an HTTP GET REST web service are the following:
document
object. This is a document
that will allow you to retrieve the URL parameters matched. These could be in the path
or the query
portion of the URL.message
that links the template document
to a message.message
which structures your response.Service
Service Operation
The final URL allowed for the service will be either:
https://ibdev.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_HR/C_REST_ECHO.v1/echo/the-parameter-we-will-echo
https://ibdev.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_HR/C_REST_ECHO.v1/echo/?value-to-echo=the-parameter-we-will-echo
There are several pieces to the URL:
ibdev.cedarhillsgroup.com
- This is the hostname. Yours will be different based on your installation.PSIGW
- Standard Integration Gateway pathRESTListeningConnector
- REST connector that accepts REST web services.PSFT_HR
- The node name that I am directing this service to. This will differ based on your installation.C_REST_ECHO
.v1 - The service operation name and version we will createecho
- A URL path we defined in the service operation.the-parameter-we-will-echo
- This is the value that will be picked up at run time that the client will send.
path
or in the query
portion of the URL depending on what URL the client uses.In REST, the URL structure matters tremendously. You need to think about your URL structure prior to implementing. Our example service here is trivial so I put zero thought into it.
You first have to build a document
object that will capture all the parameters that may be sent inbound to your web service. In this simple example, we will only have one parameter. There are some rules about a document that is used as a template.
This document can only contain primitive elements and collection elements. The document cannot contain any imports (compounds) or compound elements. – 8.55 PeopleBooks
Our web service will be really simple to start off with and only have one parameter. We will call it parameter1
.
We build a document that looks like this.
Now we have to build a message
object based on the document template we built above. I have no idea why you can’t just use the document itself. However, for some unknown reason PeopleTools requires that you create a message object.
You can do this at:
The end result is a message that basically shows the document. I told you it was useless.
We now need to create a message
that will be used to return the XML from the service. In this case, we will have our PeopleCode actually create the XML dynamically during processing. So we will create a nonrowset-based
message. This is a type of message where your code is responsible for generating the XML. It also does not generate any schemas for you automatically. You would have to add that manually.
Now we need to create a REST Service
which will “group” or “own” our service operation.
The next step is to create the service operation. You can do this from the service page. We will be providing a web service that uses the “GET” HTTP method. So we need to specify not only the desired Service Operation name but also the method.
Now that the service was created, you will see that the actual service operation name was the name we ask for but it also appended on “_GET” at the end. This will map to the HTTP method.
I highlighted a few things to make note of:
parameter1
.For REST Service Operations, we have to maintain different service operations at the HTTP method level. So if we allowed an HTTP POST and/or DELETE operation we would have additional Service operations for those. This makes sense in the Service Operation Structure because those would probably accept different HTTP Bodies so you would potentially need a different set of message objects to represent those structures. A DELETE operation does not tend to have an HTTP Body. However, an HTTP POST always has an HTTP Body.
Now we need to create an application package and class that will serve as our handler. This is the PeopleCode that will be triggered when a valid request comes into the integration broker. This code is responsible for returning data to the client.
Here is the full PeopleCode for the echo service that is in the C_REST_TEST.EchoHandler
Application Package.
import PS_PT:Integration:IRequestHandler;
class EchoHandler implements PS_PT:Integration:IRequestHandler
method EchoHandler();
method OnRequest(&msgRequest As Message) Returns Message;
method OnError(&pRequestMsg As Message) Returns string;
end-class;
method EchoHandler
/* Nothing here for now */
end-method;
method OnRequest
/+ &msgRequest as Message +/
/+ Returns Message +/
/+ Extends/implements PS_PT:Integration:IRequestHandler.OnRequest +/
Local Message &response;
&response = CreateMessage(@("Operation." | &msgRequest.OperationName), %IntBroker_Response);
Local Document &reqDOC;
&reqDOC = &msgRequest.GetURIDocument();
Local string &parm1;
&parm1 = &reqDOC.GetElement("parameter1").value;
Local XmlDoc &xmlout;
Local XmlNode &childNode;
&xmlout = CreateXmlDoc("<?xml version='1.0'?><response/>");
&childNode = &xmlout.DocumentElement.AddElement("parameter1").AddText(&parm1);
&response.SetXmlDoc(&xmlout);
Return &response;
end-method;
method OnError
/+ &pRequestMsg as Message +/
/+ Returns String +/
/+ Extends/implements PS_PT:Integration:IRequestHandler.OnError +/
Return "Error Occured";
end-method;
Let’s look at what is happening line by line in the OnRequest
method where all the magic happens.
The first section is basic setup.
We get the inbound message object, declare a document object. Then we use the GetURIDocument()
method on the request message to get to a document object.
Local Message &response;
&response = CreateMessage(@("Operation." | &msgRequest.OperationName), %IntBroker_Response);
Local Document &reqDOC;
&reqDOC = &msgRequest.GetURIDocument();
So what &reqDOC
contain at this point? It is an in memory object that maps to a document that resembles our “document template”. The integration broker will generate a document and substitute any variables sent in the URL and put those values into the document for your code to parse. The integration broker looks at the URL paths and query strings and pulls the parameters out of the URL, populates a document and communicates it to your handler via the “URIDocument” on the request message. It is a bit confusing, I know.
The next two lines you see this:
Local string &parm1;
&parm1 = &reqDOC.GetElement("parameter1").value;
We declare a &parm1
string variable to store our parameter that the client wants echoed back. Then we get the parameter1
element from the document and store it in the string variable. It is important to note that this parameter1
reference exactly matches our document template that we created. Go back and look at that screenshot above if this does not make sense.
In the next few lines, we have code that is setting up the response message object and also generating an XML document that will wrap our response echo.
Local XmlDoc &xmlout;
Local XmlNode &childNode;
&xmlout = CreateXmlDoc("<?xml version='1.0'?><response/>");
Now the final few lines add an XML element to the response and push in the value that the client sent. It then pushes the XML into the response message and returns the message.
&childNode = &xmlout.DocumentElement.AddElement("parameter1").AddText(&parm1);
&response.SetXmlDoc(&xmlout);
Return &response;
That is all there is to the handler code for this service.
Now we need to register our handler with the service operation. That is being done here:
If you care to understand the ANONYMOUS node security a bit more you should take a look at the Properly Securing the ANONYMOUS IB Node section.
Now we should have everything setup to do a test.
I would highly recommend using Postman to do your HTTP testing.
I am actually going to document the testing here in HTTP syntax as it is language neutral.
The first test will be a simple example where we pass the parameter in the path. Notice the “how-are-you-today” at the end of the URL. This matches a pattern in the service operation URI grid where “how-are-you-today” will be substituted for “parameter1” at run time.
GET /PSIGW/RESTListeningConnector/PSFT_HR/C_REST_ECHO.v1/echo/how-are-you-today HTTP/1.1
Host: ibdev.cedarhillsgroup.com
The response we get back is this:
HTTP Headers:
Content-Encoding: gzip
Content-Length: 90
Content-Type: text/xml; encoding="UTF-8"
Date: Fri, 15 Jul 2016 05:32:30 GMT
The HTTP Body is:
<?xml version="1.0"?>
<response>
<parameter1>how-are-you-today</parameter1>
</response>
Let’s try the alternative method where we pass a query string key to “value-to-echo” which will match on the second URI in the service operation setup. We are passing a string of “surfing is fun” here that is URL encoded. Remember “%20” equals a space.
GET /PSIGW/RESTListeningConnector/PSFT_HR/C_REST_ECHO.v1/echo?value-to-echo=surfing%20is%20fun HTTP/1.1
Host: ibdev.cedarhillsgroup.com
The HTML Body we get back is:
<?xml version="1.0"?>
<response>
<parameter1>surfing is fun</parameter1>
</response>
On the service operation
if you change the “Req Verification” authentication to “Basic Authentication” now the request has to come with a special HTTP header with a value that is mapped to a PeopleSoft user ID and password.
REST_TESTER
and give it a password of mamma-lumber-solemn
.REST_TESTER:mamma-lumber-solemn
UkVTVF9URVNURVI6Om1hbW1hLWx1bWJlci1zb2xlbW4=
Authorization
HTTP header in the request that looks like this: Authorization: Basic UkVTVF9URVNURVI6bWFtbWEtbHVtYmVyLXNvbGVtbg==
This is all very easy to do in Postman.
The revised HTTP signature with the authorization header looks like this:
GET /PSIGW/RESTListeningConnector/PSFT_HR/C_REST_ECHO.v1/echo/how-are-you-today HTTP/1.1
Host: ibdev.cedarhillsgroup.com
Authorization: Basic UkVTVF9URVNURVI6bWFtbWEtbHVtYmVyLXNvbGVtbg==
If you do not submit the correct Authorization header that maps to a valid user that has permission to the web service you will get an HTTP 401 (Unauthorized) status code back. Remember in REST status codes and HTTP methods are used extensively.
See REST Security for more information and best practices.
I will admit that this echo service is not very useful. However, this will give you a quick start to develop a more useful REST web service. Let’s say you wanted to return some employee level data to a client. You could take this example and replace the parameter1
value with EMPLID, then do some lookups via SQL and return the data. That part is easy.
You can also do much more complicated URL structures. Take a look at PeopleBooks for some examples. Also, you can look at the “QAS” REST services for some good examples of URL structures.