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 section, we will create a simple REST POST service that accepts data and inserts into a staging table for later processing. This is similar to the Simple REST GET Example which shows the HTTP GET Method that pulls information from PeopleSoft. Here we will explore sending data to PeopleSoft.
First we need to create a table that we will store data in. This simple web service example will take the raw data from the HTTP POST and perform a SQL Insert into a staging table.
We are going to create a simple table that accepts key/value pairs.
C_KEY_VALUE
IBTRANSACTIONID
- Key value. The IB created a unique GUID of every transaction and we will use that in our table to create a unique value.KEY1
- This will be a “duplicate key” and is a string that the payload will pass in. We will allow the same key to be sent more than once.LONGVALUE
- This is the “value” of the key and we accept a long value.ADD_DTTM
- This will be the date time that the value was inserted.In order to have the most flexibility you need to use a NonRowset Message. This will allow us to accept any data encoding and return any data encoding. I generally have a generic message like this that is shared across many web services. In this case, the message is NOT going to provide any sort of functionality for us. We just need it as a required field in the Service Operation setup. We will handle all of the decoding and encoding of data in the PeopleCode handler below.
Now we need to create a REST Service
which will “group” or “own” our service operation. It really does not provide any functionality other than organization in the IB setup and security.
Now from the Service we created above, you can create the new POST Service Operation. You see here that we enter in C_KEYVALUE
and then choose the “Rest Method” of “Post”. Choose your name wisely here as you will be stuck with this going forward and your clients will end up using this in the URLs for REST.
When you click the “Add” button, you will be transfered to the Service Operation Setup page.
We need to highlight some key points here that often cause much confusing with developers.
N_KEYVALUE_POST
. PeopleTools automatically added the “POST” to the end which ties to the HTTP method chosen. So if you plan on supporting GET, DELETE, and POST methods you will end up being 3 different service operations for those named N_KEYVALUE_GET
, N_KEYVALUE_DELETE
, N_KEYVALUE_POST
respectively. We will just be created the POST in this example.C_GENERIC
message here in the request and response.This is enough information to save the service operation. Since all of the “magic” of this web service will be handled in the PeopleCode handler, the service operation definition is just a shell in order from the Integration Broker to bootstrap our PeopleCode handler when a request comes in.
A Service Operation needs to have “routings” configured for it to be functional. This tells the IB engine what PeopleSoft nodes to send or accept messages from. In SOAP and HTTP based services, those are important and the Node Best Practices Section has some opinions documented.
In REST, PeopleSoft will handle all the Routing configurations for you and they are configured as “Any to default local node”. I have found that if you try to add routings manually it confuses the integration broker and the REST logic will NOT be triggered. This must be based on some internal PeopleTools logic. In our case, the routings look like this. There is no reason to add, remove or modify routings for REST based services. See REST Security for more information and best practices.
Right now we have a basic service operation without a handler configured and without any security applied. Let’s see what happens if we try to call this web service.
Here is the basic HTTP Request.
POST http://35.236.3.31:8000/PSIGW/RESTListeningConnector/PSFT_CS/C_KEYVALUE.v1/ HTTP/1.1
Here is the response sent back from the integration broker.
HTTP/1.1 200 OK
Connection: close
Date: Sun, 14 Mar 2021 18:23:56 GMT
Content-Length: 144
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
Set-Cookie: JSESSIONID=onkx-wDsqoMNrCdQ2SuwK4RO4CsVprPqjSZR1J9WBvCAQTEyWoft!-1454137333; path=/; HttpOnly
<HTML><HEAD><TITLE>RESTListeningConnector</TITLE></HEAD><BODY>UserID NO_ACCESS not authorized for Service Operation C_KEYVALUE_POST</BODY></HTML>
You will see from the response that it never got past the security validation. We did not send any authentication information in the request and we have NOT add this service operations to any sort of permission lists. This is important to note because the service operation configuration shown above has a Req Verification flag unchecked. That could be falsely interpreted as “this is open to the world” but that is untrue. One funky think on the tools release I am testing on this returned a HTTP 200 OK
status which is a bug.
We need a valid PeopleSoft user to be able to invoke this service operation. We are going to add this service operation to a permission list and valid user. That is covered in both the REST Security and Simple REST GET Example sections and I will assume you have read those sections and I will not cover them here again.
Up to this point we have not configured one of the most important pieces of the web service. That would be the handler
which will be an Application Class that is implemented in a certain way. Let’s establish a base working handler that we will build upon as we work through this example.
The PeopleCode handler below:
import PS_PT:Integration:IRequestHandler;
class RestPostV1 implements PS_PT:Integration:IRequestHandler
method OnRequest(&msgRequest As Message) Returns Message;
end-class;
method OnRequest
/+ &msgRequest as Message +/
/+ Returns Message +/
/+ Extends/implements PS_PT:Integration:IRequestHandler.OnRequest +/
Local Message &response = CreateMessage(@("Operation." | &msgRequest.OperationName), %IntBroker_Response);
Local XmlDoc &xmlout;
Local XmlNode &childNode;
&xmlout = CreateXmlDoc("<?xml version='1.0'?><response/>");
&childNode = &xmlout.DocumentElement.AddElement("hello").AddText("world");
&response.SetXmlDoc(&xmlout);
Return &response;
end-method;
Now we need to configure the service operation to run this PeopleCode when a request is received. That is done on the “Handler” tab of the service operation.
Now we security setup (not shown) and a handler let’s call the web service over HTTP. We will send in a request body payload but the handler is not code to do anything with it and it will be ignored.
Here is the request:
POST http://35.236.3.31:8000/PSIGW/RESTListeningConnector/PSFT_CS/C_KEYVALUE.v1/ HTTP/1.1
Authorization: Basic UkVTVF9URVNUX1VTRVI6QmFkI1Bhc3N3b3JkIzEyMw==
Content-Type: text/xml; encoding="UTF-8"
<?xml version="1.0"?>
<request>
<row>
<key>EMPLID</key>
<value>111111</value>
</row>
<row>
<key>FAVORITE_FOOD</key>
<value>Pizza</value>
</row>
<row>
<key>FAVORITE_DRINK</key>
<value>Lemo ade</value>
</row>
</request>
Here is the response:
HTTP/1.1 200 OK
Connection: close
Date: Sun, 14 Mar 2021 18:41:47 GMT
Content-Length: 72
Content-Type: text/xml; encoding="UTF-8"
Content-Encoding: gzip
Set-Cookie: JSESSIONID=dWsyC1Y0wyok2-ErWgvfiDGN3C2IetXZ0AVI43z1FQjKvZcD5sDi!-1454137333; path=/; HttpOnly,psmap=; domain=.c.peoplesoftdemo-1470578694381.internal; path=/
<?xml version="1.0"?>
<response>
<hello>world</hello>
</response>
What would happen if we tried to call this same service operation with a GET method? If you recall from above the “GET” method would actually be a separate service operation called C_KEYVALUE_GET but we did not create that. Let’s try to call it.
GET http://35.236.3.31:8000/PSIGW/RESTListeningConnector/PSFT_CS/C_KEYVALUE.v1/ HTTP/1.1
Authorization: Basic UkVTVF9URVNUX1VTRVI6QmFkI1Bhc3N3b3JkIzEyMw==
Here is the response, the HTTP Response code is 200 (Success) which is NOT the correct response code. This is an example of one of those rough edges.
HTTP/1.1 200 OK
Connection: close
Date: Sun, 14 Mar 2021 20:52:05 GMT
Content-Length: 140
Content-Type: text/html; charset=UTF-8
X-ORACLE-DMS-ECID: c8d9efad-cb10-4ec8-bc1c-a59fc852e83a-00000014
Content-Encoding: gzip
Set-Cookie: JSESSIONID=JFgygqLYRnO1h9hPakWpaFAXQ2ObIOdveA1RUkT3g1C5YrGLAuff!1814625920; path=/; HttpOnly
X-ORACLE-DMS-RID: 0
<HTML><HEAD><TITLE>RESTListeningConnector</TITLE></HEAD><BODY>Service Version Method GET for Service C_KEYVALUE.v1 not found in DB.</BODY></HTML>
Now let’s go deeper into the handler and parse the XML sent by the client and insert it into our table. Please be sure to read the Best Practices with PeopleSoft Table Updates and Inserts regarding updates.
We are going to expect XML that resembles this:
<?xml version="1.0"?>
<request>
<row>
<key>EMPLID</key>
<value>111111</value>
</row>
<row>
<key>FAVORITE_FOOD</key>
<value>Pizza</value>
</row>
<row>
<key>FAVORITE_DRINK</key>
<value>Lemo ade</value>
</row>
</request>
rows
.row
, we are expecting a key
and value
node which we will use to insert into out key value table C_KEY_VALUE.Here is the completed handler that will:
|
|
Here is a full request.
POST http://35.236.3.31:8000/PSIGW/RESTListeningConnector/PSFT_CS/C_KEYVALUE.v1/ HTTP/1.1
Authorization: Basic UkVTVF9URVNUX1VTRVI6QmFkI1Bhc3N3b3JkIzEyMw==
Content-Type: text/xml; encoding="UTF-8"
<?xml version="1.0"?>
<request>
<row>
<key>EMPLID</key>
<value>111111</value>
</row>
<row>
<key>FAVORITE_FOOD</key>
<value>Pizza</value>
</row>
<row>
<key>FAVORITE_DRINK</key>
<value>Lemonade</value>
</row>
</request>
The response that came back from our handler is:
HTTP/1.1 200 OK
Connection: close
Date: Sun, 14 Mar 2021 21:24:15 GMT
Content-Length: 203
Content-Type: text/xml; encoding="UTF-8"
Content-Encoding: gzip
Set-Cookie: JSESSIONID=R8kyoBYAGiP-cljZYIDnd2gWkm3P56EG4x1mW8LCLHFiY_rzJP1R!1814625920; path=/; HttpOnly,psmap=; domain=.c.peoplesoftdemo-1470578694381.internal; path=/
<?xml version="1.0"?>
<response>
<META isMETA="True">
<OPRID>REST_TEST_USER</OPRID>
<CURRENT_TIME>2021-03-14-21.24.15.000000</CURRENT_TIME>
<TRANSACTION_ID>a0e158cd-850b-11eb-a700-cd5c40da7841</TRANSACTION_ID>
<DBNAME>CS92U009</DBNAME>
</META>
</response>
Here we can see the data was inserted into our table.