Workday Reports as SOAP Services in WD Studio


Why use SOAP for RaaS?

You may find yourself looping through a data set (such as an input file) amd performing some kind of input logic that requires data from a Workday custom report which accepts a particular object instance as a parameter. Generally, RaaS calls are expensive operations, and running a report for each individual worker/cost center/period/whatever can quickly become a pain point as your input set grows. You're nearly always better off running a report once while passing every instance you'll need in a single call, and retrieving all the relevant data up front (if memory permits.) In the past year alone:

I should mention that it is technically possible to pass multiple instances inside a URL if you wanted to stick with the REST approach. For example, a multi instance worker report could be called with something like the MVEL below (assuming you've added a multi-instance reference-type launch parameter and a report service with a reference to a report that takes multiple workers as input to your Workday-In):
https://wd-url/ccx/service/customreport2/tenant/owner/Report_Name?Worker!WID=418b91b6b064104b21a9ee0d6c2498ab!6854645811284e8182713524d52a30ce
and with a list of Worker WIDs you could construct a URL in an eval step with something like this:
props['Worker_WIDs'] = lp.getReferenceDataList('Workers', 'WID')
props['report_url'] = intsys.reportService.getExtrapath('WorkerReport') + '?Worker!WID='
props['count'] = props['Worker_WIDs'].size() - 1
foreach(i: count) { props['report_url'] = props['report_url'] + '!' + props['Worker_WIDs'].get(i) }
but it's likely that you're going to run into URL length limitations. Most browsers limit URLS to around 2083 characters and while I haven't found anything published, I imagine Workday Studio's limit is around there as well; With 32 characters for each WID you're most likely going to hit that limit pretty quickly. (Not to mention that appending strings inside a loop like that can eat memory suprisingly quickly - if you must do this, you're probably better off using java.util.StringBuilder's append() method) Fortunately, Workday RaaS also publishes reports as SOAP web services, in which request parameters can be sent in the message body. Message length is less of a concern (I know of one integration that sends a few thousand workers in a single report call) and it's easy to construct the request in an XSL or write step rather than a chain of eval statements.

You'll first want to ask yourself if there's an easier way before going down this road, such as building your report filter around some other, more manageable (i.e. singular, or static) parameter. You've probably already considered this, but it's worth taking a few minutes to think over. If you still want or need to go this route, please read on.

How it's done

Start by creating a report and publishing it as a web service, as you would with an EIB or REST-based RaaS report. Off the reports related action, export and save the WSDL locally.

Open your studio project, and from the context menu on the project root folder, select 'Import->Import...' select on the following prompt, select 'File System' and click 'Next'.

Navigate to wherever you saved the WSDL earlier and select the file. Select your project root folder (or a subfolder if you wish) as the destination, and click 'Finish' to bring the WSDL into your project.
On the Schema Explorer to the right, click the leftmost 'Add WSDL or XSD' button, navigate to your newly imported WSDL, and click 'OK'.

You should now see a representation of your report in the 'Schema Explorer' pane. Expand it and you'll see ports for SOAP and REST access to your report. Expand the SOAP port and you'll see the 'Execute_Report' operation; From here, you can right click and 'Open SOAP wrapped request in Web Service Tester' as you would with a delivered Workday Web Service, and construct a request via XSL or a 'write' step.

The request portion of your studio will look something like the above. It's not all that different than calling a Workday Web Service, though there are a few things to keep in mind:
Create a report reference on your Workday-in, and point it to your report. Instead of a Workday-out-SOAP you'll use a standard http-out component and pass a reference in the 'Endpoint' property:

Add a WSSE Header to your request, using the $wss.usernametoken.username and $wss.usernametoken.password variables, so that your report is called with the credentials under which the studio is run. Make sure your integration user has the security needed for the report.

In your response chain, a validate step with an expression similar to the following can be used to trap SOAP faults:

parts[0].xpath('SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault', 'SOAP-ENV http://schemas.xmlsoap.org/soap/envelope/') == ''
Of course, you could add a namespace alias for SOAP-ENV if you're going to be doing anything more with the envelope data. Similarly, a copy step with an input of 'soapbody' and an output of 'message' can be used to strip the SOAP envelope if you're particular about that sort of thing.

Structuring data for performance

At this point, you'll have a large block of XML which you can store in a variable, and extract individual elements as needed with xpath. However, xpath lookups are themselves kind of expensive (though much less so than a new report call each time.) For large datasets, it's probably worth it to convert your giant XML result set into a hashtable, as hash lookups are relatively quick.
The process for this will look something like the sequence below:

In your first Eval step, prepare a hashmap to store the report results, as below:
props['report.hash.map'] = new java.util.HashMap()
Split your report output into individual records, and read each key and value into the table you created with something similar to the foll
props['report.hash.key.value'] = parts[0].xpath('/rp:Report_Entry/rp:Employee/rp:Employee_ID')
props['report.hash.map'].put(props['report.hash.key.value'], parts[0].text)
You should now be able to access the report data you need with a simple map lookup, which will run somewhat faster than an xpath statement, which itself will run an order of magnitude faster than a report call.
That's about all there is to it. A sample studio file is available here.
Hope this helps.


2015 @matthewrichen mrichen.github.io/wdlearn/