Reporting Web Services: Using the REST Web Services to run a Query
By Chris Malek | Tue, May 3, 2016
I had previously posted an article about Running a PeopleSoft Query using the Reporting Web Services. We assume you have read that article. That former article covered how to execute a PeopleSoft query using the HttpListeningConnector
which requires an HTTP post and the web service parameters to be located in the HTTP Request body.
In this article we are going to look at how the REST-based Reporting Web Services can be used instead. We will see that using the REST services is a little more “clean” and requires less overhead on the client. After all REST is best!
Evolution of REST Reporting Web Services
Just in case you did not read that formerly mentioned article it will be useful to give a little background into what the “Reporting Web Services” are. PeopleTools delivers some functionality called the “Reporting Web Services” which allows a third party to execute a PeopleSoft Query over a web service. There are several different execution models documented in the Reporting Web Services PeopleBooks. However, we are going to cover only the synchronous method which the query results will be run in real-time and an XML response will be returned while the client waits on the line. This is the most simple approach and requires the least amount of code for the third party. There are also web services for getting meta-data on queries as well as creating query definitions from outside systems.
This query web service can be an easy way for external systems to pull data out of PeopleSoft. You don’t have to create a new web service for each new data extract. You get a functional user to create the query, ensure your query security is setup and communicate the new parameters to the client.
When the “Reporting Web Services” were first released, they were only delivered using standard Service Operations that you posted to the HttpListeningConnector
or the PeopleSoftServiceListeningConnector
if you wanted SOAP. When PeopleTools started to support REST endpoints via the RESTListeningConnector
these web services were ported over to the REST model.
Now there are really two versions of these web services: REST and “Standard”. The REST versions are all contained under the QAS_QRY_REST
service and the standard/old operations are contained under the QAS_QRY_SERVICE
service definition.
In the screenshot below, I searched for any service operations whose service name started with “QAS”, then sorted by the Service Operation name. I also highlighted in yellow the REST versions of the services.
Note: Remember that a SERVICE “owns” and SERVICE OPERATION.
What you will see here is that there are 2 versions of the service operations. The ones that are REST-based typically have “REST_GET” suffix. So for example, you will see the QAS_LISTQUERY_OPR and QAS_LIST_QERY_REST_GET which are basically the same service. The former being “standard” and the latter being REST.
You will also notice a few that have a “REST_POST” suffix. These are ones that require an HTTP Post as they are creating something in the system. This is in-line with standard REST design principles.
Security Setup
In order to run these web services we need to create a PeopleSoft account that has access to both the query objects and the web services. There are several ways to secure PeopleSoft REST Services. We are going to take a simple approach here and use “Basic” authorization.
- First we need to create a new Permission List: RESTUSER with the following grants.
- Web Services Authorizations: Service: QAS_QRY_REST, Service Operation: QAS_EXECUTEQRY_REST_GET
- Query Permissions: Check - “Only Allowed to run Queries”
- Query Access Group Permissions - Grant whatever tree levels you need here for the user to be able to access the records on the query.
- This is very specific to each installation. Please check with your security team.
- Next lets create a role called
RESTUSER
.- This role should have only one permission list of
RESTUSER
.
- This role should have only one permission list of
- Now we need to create a PeopleSoft user that can execute our query. This is a standard OPRID in the PSOPRDEFN table.
- OPRID:
RESTUSER
- Password:
$ecretknock1234
- OPRID:
We are going to use “Basic Authorization” in the web service calls below. This involves an HTTP header that looks like this Authorization: Basic some-value-that-identifies-you-to-the-server
.
The value that you pass is in this form Base64Encode(OPRID:PASSWORD). So in our case we will take user name concatenated with “:” and the password. This gives us a string equal to “RESTUSER:$ecretknock1234”. We then BASE64 encode that string which results in “UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0” which you will see in the requests below.
First Query - No Prompts
First we are going to create a query called USERS_IN_ROLE
. It is a simple query that has no prompts and returns one column. Here is the SQL.
SELECT A.ROLEUSER
FROM PSROLEUSER A
WHERE ( A.ROLENAME = 'Portal Administrator')
Lets call the query web service. Here is the HTTP signature of that web service call.
GET /PSIGW/RESTListeningConnector/PSFT_CHGDEM/ExecuteQuery.v1/PUBLIC/USERS_IN_ROLE/XMLP/NONFILE?isconnectedquery=n&maxrows=3 HTTP/1.1
Host: demo.cedarhillsgroup.com
Authorization: Basic UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0
The response from the server is:
<?xml version="1.0"?>
<QAS_GETQUERYRESULTS_RESP_MSG xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_GETQUERYRESULTS_RESP_MSG.VERSION_1">
<query numrows="3" queryname="USERS_IN_ROLE" xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_QUERYRESULTS_XMLP_RESP.VERSION_1">
<row rownumber="1">
<ROLEUSER>
<![CDATA[AA_USER]]>
</ROLEUSER>
</row>
<row rownumber="2">
<ROLEUSER>
<![CDATA[ACA_USER]]>
</ROLEUSER>
</row>
<row rownumber="3">
<ROLEUSER>
<![CDATA[ADM_USER]]>
</ROLEUSER>
</row>
</query>
</QAS_GETQUERYRESULTS_RESP_MSG>
There are a few things to note about the URL.
- My PeopleSoft local node name is: PSFT_CHGDEM
- The request has a path and query string that looks like this:
ExecuteQuery.v1/PUBLIC/USERS_IN_ROLE/XMLP/NONFILE?isconnectedquery=n&maxrows=3
. Inside that we see that:- We are limiting the rows to 3 with the “maxRows” parameters
- We are telling it what query name to run: USERS_IN_ROLE
- We want a XMLP data format back.
- We want a NONFILE response type.
If you contrast this with the “standard”/SOAP method of calling these services you basically get the same result. However, the location of the parameters are completely in the URL path and query string instead of the HTTP Post Body.
REST Service Operation Signatures
How do you know what the parameters are and in what order? When you define a REST service operation in PeopleTools you define a “template” which are the different path and parameters signature combinations. Here is a screenshot of the QAS_EXECUTEQRY_REST_GET parameters. Note that I had to expand the template sections to make them viewable in the grid. If you look at this in your your PeopleSoft environment, not all the text is visible.
Your requests have to match one of theses templates for it to pass into a handler to be processed. In the first example above, we matched on the number 6 template.
Query Example with 1 Prompt
Let’s take this one step farther. Let’s add a query prompt to the equation and see how we can pass that to the web service. First we create a new query called USERS_IN_ROLE_PROMPT
. It has the following SQL.
SELECT A.ROLEUSER
FROM PSROLEUSER A
WHERE ( A.ROLENAME = :1)
The “:1” query prompt is defined as “BIND1” which we will need in the HTTP request.
In order for the client to pass the prompts, new query string parameters must be included to pass the bind name and value. We want to pass a value of “Portal Administrator” as the value for “BIND1”. When we map that to the template for the web service, you add in the following query string parameters.
&prompt_uniquepromptname=BIND1,BIND2&prompt_fieldvalue=VALUE1,VALUE2
The request looks like this:
GET /PSIGW/RESTListeningConnector/PSFT_CHGDEM/ExecuteQuery.v1/PUBLIC/USERS_IN_ROLE_PROMPT/XMLP/NONFILE?isconnectedquery=n&maxrows=3&prompt_uniquepromptname=BIND1&prompt_fieldvalue=Portal Administrator HTTP/1.1
Host: demo.cedarhillsgroup.com
Content-Type: application/xml
Authorization: Basic UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0
Cache-Control: no-cache
The output would be:
<?xml version="1.0"?>
<QAS_GETQUERYRESULTS_RESP_MSG xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_GETQUERYRESULTS_RESP_MSG.VERSION_1">
<query numrows="3" queryname="USERS_IN_ROLE_PROMPT" xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_QUERYRESULTS_XMLP_RESP.VERSION_1">
<row rownumber="1">
<ROLEUSER>
<![CDATA[CMALEK]]>
</ROLEUSER>
</row>
<row rownumber="2">
<ROLEUSER>
<![CDATA[TESTUSER]]>
</ROLEUSER>
</row>
<row rownumber="3">
<ROLEUSER>
<![CDATA[PS]]>
</ROLEUSER>
</row>
</query>
</QAS_GETQUERYRESULTS_RESP_MSG>
If you had more bind variables, you would then just include several key values pairs in this form.
&prompt_uniquepromptname=BIND1&prompt_fieldvalue=VALUE1&prompt_uniquepromptname=BIND2&prompt_fieldvalue=VALUE2
Filter Field Example
If you look at the templates for the QAS_EXECUTEQRY_REST_GET service operation you will see some of them have a “filterfields” paramater. This looks interesting. Let’s see what it does.
First let’s add a few more columns to the query definition. We add here ROLENAME and DYNAMIC_SW.
SELECT A.ROLEUSER, A.ROLENAME, A.DYNAMIC_SW
FROM PSROLEUSER A
WHERE ( A.ROLENAME = :1)
If you run that query via the web service you now get back this result.
<?xml version="1.0"?>
<QAS_GETQUERYRESULTS_RESP_MSG xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_GETQUERYRESULTS_RESP_MSG.VERSION_1">
<query numrows="3" queryname="USERS_IN_ROLE_PROMPT" xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_QUERYRESULTS_XMLP_RESP.VERSION_1">
<row rownumber="1">
<ROLEUSER>
<![CDATA[CMALEK]]>
</ROLEUSER>
<ROLENAME>
<![CDATA[Portal Administrator]]>
</ROLENAME>
<DYNAMIC_SW>
<![CDATA[N]]>
</DYNAMIC_SW>
</row>
<row rownumber="2">
<ROLEUSER>
<![CDATA[TESTUSER]]>
</ROLEUSER>
<ROLENAME>
<![CDATA[Portal Administrator]]>
</ROLENAME>
<DYNAMIC_SW>
<![CDATA[N]]>
</DYNAMIC_SW>
</row>
<row rownumber="3">
<ROLEUSER>
<![CDATA[PS]]>
</ROLEUSER>
<ROLENAME>
<![CDATA[Portal Administrator]]>
</ROLENAME>
<DYNAMIC_SW>
<![CDATA[N]]>
</DYNAMIC_SW>
</row>
</query>
</QAS_GETQUERYRESULTS_RESP_MSG>
Let’s imagine that we only care about the ROLEUSER and DYNAMIC_SW field and we do NOT want the ROLENAME back because we are passing it as a parameter and we will already know the value. There is a URI in the service operation that has this parameter: &filterfields={FilterFields*}
. It is supposed to allow this this.
PeopleBooks mentions this:
FilterFieldName : List of field names to be returned. This value is case sensitive and must be the unique field name as returned by the service operation QAS_LISTQUERYFIELDS.
You are starting to see this pattern alot in single page web applications (SPWA) where some javascript will call a REST service that may have many different clients. The service may return alot of data. However, the SPWA may only care about 5 fields out of the 100. Therefore, it asks the server to only return those 5 fields if possible. This filterfields is supposed to follow that same basic approach.
So let’s grant our user RESTUSER access to the QAS_LISTQUERYFIELDS_REST_GET
service operation (an exercise for the reader) and execute that web service for our query.
GET /PSIGW/RESTListeningConnector/PSFT_CHGDEM/QueryFields.v1/USERS_IN_ROLE_PROMPT?isconnectedquery=N HTTP/1.1
Host: demo.cedarhillsgroup.com
Accept: application/xml
Authorization: Basic UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0
The response is returns the fields that are defined in our query definition.
<?xml version='1.0'?>
<QAS_LISTQUERYFIELDS_RESP_MSG xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_LISTQUERYFIELDS_RESP_MSG.VERSION_1">
<QAS_LISTQUERYFIELDS_RESP>
<PTQASWRK class="R" xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_LISTQUERYFIELDS_RESP.VERSION_1">
<QueryName>USERS_IN_ROLE_PROMPT</QueryName>
<PTQASFIELDWRK class="R">
<ColumnNumber>1</ColumnNumber>
<FieldName>ROLEUSER</FieldName>
<FieldType>string</FieldType>
<FieldLength>30</FieldLength>
<FieldDecimal>0</FieldDecimal>
<HeadingText>User ID</HeadingText>
<UniqueFieldName>A.ROLEUSER</UniqueFieldName>
</PTQASFIELDWRK>
<PTQASFIELDWRK class="R">
<ColumnNumber>2</ColumnNumber>
<FieldName>ROLENAME</FieldName>
<FieldType>string</FieldType>
<FieldLength>30</FieldLength>
<FieldDecimal>0</FieldDecimal>
<HeadingText>Role Name</HeadingText>
<UniqueFieldName>A.ROLENAME</UniqueFieldName>
</PTQASFIELDWRK>
<PTQASFIELDWRK class="R">
<ColumnNumber>3</ColumnNumber>
<FieldName>DYNAMIC_SW</FieldName>
<FieldType>string</FieldType>
<FieldLength>1</FieldLength>
<FieldDecimal>0</FieldDecimal>
<HeadingText>Dynamic</HeadingText>
<UniqueFieldName>A.DYNAMIC_SW</UniqueFieldName>
</PTQASFIELDWRK>
</PTQASWRK>
</QAS_LISTQUERYFIELDS_RESP>
</QAS_LISTQUERYFIELDS_RESP_MSG>
So the UniqueFieldName
for the user ROLEUSER field is “A.ROLEUSER”. Lets see what happens when we try to tell the query web service to only return that one field even though the query definition has 3 fields.
GET /PSIGW/RESTListeningConnector/PSFT_CHGDEM/ExecuteQuery.v1/PUBLIC/USERS_IN_ROLE_PROMPT/XMLP/NONFILE?isconnectedquery=n&maxrows=3&prompt_uniquepromptname=BIND1&prompt_fieldvalue=Portal Administrator&filterfields=A.ROLEUSER HTTP/1.1
Host: demo.cedarhillsgroup.com
Accpet: application/xml
Authorization: Basic UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0
The response back from the server is:
<?xml version="1.0"?>
<QAS_GETQUERYRESULTS_RESP_MSG xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_GETQUERYRESULTS_RESP_MSG.VERSION_1">
<query numrows="3" queryname="USERS_IN_ROLE_PROMPT" xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_QUERYRESULTS_XMLP_RESP.VERSION_1">
<row rownumber="1"/>
<row rownumber="2"/>
<row rownumber="3"/>
</query>
</QAS_GETQUERYRESULTS_RESP_MSG>
What the heck! It looks like a big fat fail whale! I am writing this article using an 8.54 tools release.
It looks like there is a bug there with those filterfield
parameters. You can see that 3 rows did come back but there is no data in there. Maybe I used the wrong field name. Just for fun lets try using just “ROLEUSER” instead of “A.ROLESER” to see if maybe we did not use the right field name.
Making that one substitution
GET /PSIGW/RESTListeningConnector/PSFT_CHGDEM/ExecuteQuery.v1/PUBLIC/USERS_IN_ROLE_PROMPT/XMLP/NONFILE?isconnectedquery=n&maxrows=3&prompt_uniquepromptname=BIND1&prompt_fieldvalue=Portal Administrator&filterfields=ROLEUSER HTTP/1.1
Host: demo.cedarhillsgroup.com
Authorization: Basic UkVTVFVTRVI6JGVjcmV0a25vY2sxMjM0
Accept: application/xml
You get this back.
<HTML>
<HEAD>
<TITLE>RESTListeningConnector</TITLE>
</HEAD>
<BODY>The fields received in the fields filter do not match the query (228,5) PT_QAS.PT_QES.QASExecutionService.OnExecute Name:ValidateQuery PCPC:57704 Statement:759
Called from:PT_QAS.PT_QES.QASExecutionService.OnExecute Name:ExecutePSQueryImp Statement:337
Called from:PT_QAS.PT_QES.QASExecutionService.OnExecute Name:ExecuteQuerySyncRequest Statement:272
Called from:PT_QAS.QASRequestHandler.OnExecute Name:ProcessQASRequest Statement:30
Called from:QAS_EXECUTEQRYSYNC.RequestHandler.OnExecute Name:OnR</BODY>
</HTML>
There are a few things to note about this response.
- It looks like “A.ROLEUSER” in the original attempt was correct.
- The response is actually HTML. The response header is
Content-Type: text/html; charset=UTF-8
and you can see the HTML source. The request told the server via theaccept
HTTP request header that she only takes XML. However, HTML was sent back. :-( - The HTTP Status code returned is actually
HTTP/1.1 200 OK
which is definitely NOT correct.- This scenario is more likely a
400 Bad Request
because the request is malformed.
- This scenario is more likely a
These issues could present a problem with some programmatic access to these web services. As you can see they have some rough edges that Oracle needs to work out.
Additional Reading
Article Categories
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 ChrisPeopleSoft 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.
Integration Broker - The Missing Manual
I am in the process of writing a book called "Integration Broker - The Missing Manual" that you can read online.