Author Info
Chris Malek

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 Chris
Looking for pain-free PeopleSoft web services? 😀
PeopleSoft Simple Web Services (SWS)

Introducing 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.

Contents

A Complete PeopleSoft REST GET Web Service Example

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.

  • It will be an simple “echo” service that echoes back what was given in the URL query path.
  • We will return XML because JSON support in PeopleSoft is a bit painful at the time of writing even on the latest tools release.
  • We will first use no authentication then show how we can use “basic authentication” which is tied to an OPRID.

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:

  • Build a “Template” 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.
  • Create a new message that links the template document to a message.
  • Create your response message which structures your response.
  • Create a REST Service
  • Create your Service Operation
  • Create your service operation handler application package. This is the PeopleCode that will trigger and will respond to the incoming request and return something useful to the client.
  • Link your service operation handler to the application class.
  • Setup the security of the web service.
  • Test

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 path
  • RESTListeningConnector - 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 create
  • echo - 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.
    • We will be able to pass this in the URL 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.

Build the Template Document

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.

Build New Message linked to Template Document

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:

  • Choose Add New Message
  • Choose Type = “Document”
  • Enter in your desired message name and then input the package document package and name in the boxes.

The end result is a message that basically shows the document. I told you it was useless.

Creating the Response Message

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.

Creating the Service

Now we need to create a REST Service which will “group” or “own” our service operation.

Creating the 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:

  • We are going to put in 2 different “URI” syntaxes where this service can be called.
    • You will see that we have some curly braces in the URI grid. Those are variables that will be substituted at run-time into our “document template” and our handler code can pick them up. You can only put variable names in the URI section that match data elements in your “document template”. This really confused me when I first started to look at PeopleSoft REST services. If this does not make sense now look closely at the URI grid and the document template created above and look at the names specifically parameter1.
  • We input the document template message name in the appropriate place and we also specified the return message.
    • In our case we are returning XML, so that is chosen as the return content type.
  • In the first iteration we will NOT have any authentication turned on to make testing easier.

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.

Creating the Service Operation Handler

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.

Linking the Handler Code to the Service Operation

Now we need to register our handler with the service operation. That is being done here:

Setting Up Service Operation Security

  • REST service operations are NOT tied to nodes or configured to have “routings” setup at a node level like the “old” service operations.
  • In the current setup that we have so far, we have no authentication on the Service Operation.
  • All PeopleCode has to run under some user context. So what user ID do we need to give permission to for this service operation? In the current configuration the node “ANONYMOUS” will be used because no other users have been given permission. The user id that is attached to that ANONYMOUS node has to have security to this new service operation. There was no routing setup to this node but the integration broker uses this to find a default user if one is not provided. The ANONYMOUS node is the fall-back user. So if you want your web service to be open to the world then you need to make sure your ANONYMOUS node has a valid user defined and that the user has access to the service operation via some permission list. I will not document that as it is pretty standard.
    • This is NOT how you will setup your web service in your production environment. I am only mentioning this step for educational purposes.
    • We will cover authentication later in this section.

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.

Testing the Echo Service

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>

Setup up Basic Authentication

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.

  • So let’s say that we create a new PeopleSoft OPRID of REST_TESTER and give it a password of mamma-lumber-solemn.
  • You need to make sure this user has access to the service operation via a permission list.
  • You then have to take the user name and password and concatenate it together with a colon. That will give you REST_TESTER:mamma-lumber-solemn
  • Now you have to BASE64 encode that string which will give you: UkVTVF9URVNURVI6Om1hbW1hLWx1bWJlci1zb2xlbW4=
  • Now you have to pass an 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.

Exploring Further and More Use case

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.