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.
PeopleTools REST Web Services come with some ability to cache the response data. At the time of writing, there is zero documentation from Oracle on this. 😒
Why would you want to cache a REST response?
This REST Caching has nothing to do with PeopleTools object caching like with PeopleCode or pages. This is different.
message
object called SetRESTCache
that takes a date-time parameter for how long you want the response cached.
SetRESTCache
method is called on the response message. This is subtle and not covered in the documentation or code sample in PeopleBooks.SetRESTCache
on the request message object which made sense to me because it was the request signature that should be marked in the cache. However, that was incorrect. The response message object is responsible for triggering the cache.%operator
or %employeeid
you probably do NOT want to use caching. See information below. You have been warned!!!GET
operations.JSESSIONID
cookie returned on each response. This makes sense because this is coming from weblogic prior to the PeopleSoft code.%IntBroker.DeleteRESTCache
. It looks like this: &b_ret = %IntBroker.DeleteRESTCache(&op, &ver);
where &op
is the operation name and &ver
is the version.For this example, we have a very simple REST GET Service Operation.
The trivial handler without any caching looks like this. It returns an XML document with the current time and the current user.
import PS_PT:Integration:IRequestHandler;
class handler 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 &msgReturn;
&msgReturn = CreateMessage(@("Operation." | &msgRequest.OperationName), %IntBroker_Response);
Local XmlNode &childNode;
Local XmlDoc &xmlout;
&xmlout = CreateXmlDoc("<?xml version='1.0'?><response/>");
&childNode = &xmlout.DocumentElement.AddElement("system-time").AddText(String(%Datetime));
&childNode = &xmlout.DocumentElement.AddElement("current-user").AddText(%OperatorId);
&msgReturn.SetXmlDoc(&xmlout);
Return &msgReturn;
end-method;
A sample response would look like this:
<?xml version="1.0"?>
<response>
<system-time>2019-09-06-20.57.34.000000</system-time>
<current-user>PS</current-user>
</response>
To call this web service the HTTP Syntax would look like this with user “PS” and Password “Hello123”
GET http://testib.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_CS/CHG_REST_CACHE.v1/ HTTP/1.1
Authorization: Basic UFM6SGVsbG8xMjM=
If we want to add caching of the response then we just need to add a few lines of code before the function returns. The full revised handler is below. We are creating an datetime variable 2 minutes in the future and passing that to the SetRESTCache
method on the response message.
import PS_PT:Integration:IRequestHandler;
class handler 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 &msgReturn;
&msgReturn = CreateMessage(@("Operation." | &msgRequest.OperationName), %IntBroker_Response);
Local XmlNode &childNode;
Local XmlDoc &xmlout;
&xmlout = CreateXmlDoc("<?xml version='1.0'?><response/>");
&childNode = &xmlout.DocumentElement.AddElement("system-time").AddText(String(%Datetime));
&childNode = &xmlout.DocumentElement.AddElement("current-user").AddText(%OperatorId);
&msgReturn.SetXmlDoc(&xmlout);
/* Caching Begin */
Local datetime &TwoMinutesInFuture;
&TwoMinutesInFuture = AddToDateTime(%Datetime, 0, 0, 0, 0, 2, 0);
&msgReturn.SetRESTCache(&TwoMinutesInFuture);
/* Caching End */
Return &msgReturn;
end-method;
So now if you call the web service with the exact same path and query string parameters, the integration broker will NOT run the handler for 2 minutes and the cache will be used. The cache will be used until it expires.
?cachebuster={{randomnumber}}
or ?cachebuster={{datetime}}
https://cedarhillsgroup.com/ib/aboutme
That service may take the current user context and generate a response based on the user calling the web service. All users call the exact same URL. The first person to call that web service at that URL would cause it to be cached. Then another user may call the same URL and get the response of the other user!!! There is a detailed example of this below. Do not use the caching operation if your handler returns information about the current user and the URL path or query string does not designate that unique user in the request.As we discussed above, the first user to call the web service at a specific path signature will trigger a cache. The second user will get the cached response of the first user if the exact same path is used. So if the response has information that is contextual to the current user logged in, the second user will get the information from the first user. Obviously the is NOT what you want.
Let’s look at an example of this. We will use our simple example above. We will have two different authorized users: PS & PS2. We will see if we call the service for PS then PS2, PS2 will see a response that has the “PS” user referenced. The only thing that changes between the calls is the authorization header.
First call by PS:
GET http://testib.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_CS/CHG_REST_CACHE.v1/ HTTP/1.1
Authorization: Basic UFM6SGVsbG8xMjM=
The response:
HTTP/1.1 200 OK
Connection: close
Date: Fri, 06 Sep 2019 21:23:37 GMT
Content-Length: 115
Content-Type: text/xml; encoding="UTF-8"
Content-Encoding: gzip
<?xml version="1.0"?>
<response>
<system-time>2019-09-06-21.22.49.000000</system-time>
<current-user>PS</current-user>
</response>
The second call made by user PS2 within the “cache window” is:
GET http://testib.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_CS/CHG_REST_CACHE.v1/ HTTP/1.1
Authorization: Basic UFMyOkhlbGxvMTIz
It gets the exact same response with the “current-user” node showing the first PS user. This could be undesirable depending on your use case.
HTTP/1.1 200 OK
Connection: close
Date: Fri, 06 Sep 2019 21:24:06 GMT
Content-Length: 115
Content-Type: text/xml; encoding="UTF-8"
Content-Encoding: gzip
<?xml version="1.0"?>
<response>
<system-time>2019-09-06-21.22.49.000000</system-time>
<current-user>PS</current-user>
</response>
If the second user changed any part of the query string or path, then the cache would not be used. For example, we will add a “foo=bar” query string parameter that only user PS2 has called and that will run the handler.
GET http://testib.cedarhillsgroup.com/PSIGW/RESTListeningConnector/PSFT_CS/CHG_REST_CACHE.v1/?foo=bar HTTP/1.1
Authorization: Basic UFMyOkhlbGxvMTIz
HTTP/1.1 200 OK
Connection: close
Date: Fri, 06 Sep 2019 21:27:57 GMT
Content-Length: 116
Content-Type: text/xml; encoding="UTF-8"
Content-Encoding: gzip
<?xml version="1.0"?>
<response>
<system-time>2019-09-06-21.27.57.000000</system-time>
<current-user>PS2</current-user>
</response>
I tried getting information from Oracle Support but they were not helpful.