Exploring Web Services with SAS®
Author(s): Richard Carey
Web services are the building blocks of the APIs that drive the modern web. From Amazon Web Services to Philips Hue light bulbs, web services enable almost limitless integration. In this paper, we explore what a web service is and how we can use them via SAS®.
We look at mechanisms to call web services from SAS using the HTTP and SOAP procedures, how to create web services from SAS® Stored Processes using SAS® BI Web Services, and consider the future of web services and SAS with SAS® Viya®, along with some practical examples.
This paper aims to showcase calling and developing web services using the tools and techniques available in SAS. As a SAS user, you are well placed to take advantage of the proliferation of web-based API’s available today.
As well as calling web services, SAS Integration Technologies provides the SAS BI Web Service web application, allowing you to surface the power of SAS to your organisation via a SOAP and REST based web services interface.
This paper assumes a basic knowledge of the HTTP protocol, and the XML and JSON data formats.
What is a Web Service?
The W3C defines a web service as “a software system designed to support interoperable machine-to- machine interaction over a network” (World Wide Web Consortium, 2004).
That is a very broad definition; for the purposes of this paper, we will narrow it to look at services that communicate via HTTP, intended for consumption by another machine rather than a user directly.
Put simply, web services allow disparate applications and services to share data and functionality. For example, many businesses will embed a Google Map of their location on their website, phone apps offer integration with social media, and Siri can read you the weather forecast for your current location. All of these rely on the integration of functionality provided by disparate services, published via an API and accessed over HTTP.
The “Internet of Things” is also driving change in this area. Everything from light bulbs to refrigerators are now connected to the internet. Your phone can turn on your lights as you approach home, your fridge can order food when it notices you are running low.
SAS has all the necessary tools to take part in this revolution. Ok, you might not need to use SAS to order your weekly food shop but, as this paper will show, you could if you wanted to!
1.2 A Word on REST, SOAP, and Other Standards
There are several web service protocols available that present standardised frameworks for building and consuming web services. Two of the most prevalent are SOAP (Simple Object Access Protocol) and REST (REpresentational State Transfer). The majority of modern web service API’s are RESTful services, although you will still find SOAP services within the enterprise and older applications.
1.2.1 SOAP Services
The SOAP protocol defines the web service message structure and a mechanism for describing procedure calls and responses. Communication with a SOAP web service is handled with XML messages and can be transmitted over any reliable communication protocol.
The functionality provided by a SOAP service is commonly described by an XML file in the Web Service Description Language (WSDL) format. This file defines the input XML structure required by the service and the structure to expect as output.
1.2.2 RESTful Services
RESTful services are built to an architectural style rather than a strict protocol like SOAP. They make use of the HTTP stateless operators (often referred to as verbs) such as “GET”, “POST” or “PUT”, to operate on resources identified with Uniform Resource Locators (URLs).
Message format is not restricted, but is most often XML, JSON or HTML.
Calling Web Services from SAS
SAS provides two main procedures for interacting with web services, the HTTP procedure and the SOAP procedure. They both follow the following broadly similar logical process; set up any input required (the request), call the service passing the request file as input, then process the output (the response).
However, proc SOAP is written specifically to call SOAP web services, whereas proc HTTP is more generalised and flexible in areas such as method specification and authentication support. We will focus on the HTTP procedure here.
2.1 The HTTP Procedure
The HTTP procedure issues Hypertext Transfer Protocol requests. As such, it can support most RESTful web services, as well as SOAP.
2.1.1 No Input Required
In this example we call a service provided by NASA, the Near Earth Object Web Service, to list asteroids passing close to the earth:
The FILENAME statement sets up a temporary output file to hold the web service response.
The HTTP procedure is used to call the URL of the service, setting the METHOD option to “GET” (the HTTP verb), and the OUT option to the “resp” fileref.
The output from the service is JSON formatted, so the JSON libname engine is used to read in the response via the “resp” fileref, which is then printed using the PRINT procedure. Figure 1 shows the output from PROC PRINT:
Figure 1 – Output from the Call to the Near Earth Object Web Service
More complex JSON can be accessed using the JSON libname engine’s “map” feature, similar to using an XML map to read XML formatted data.
2.1.2 Providing Input
There are several common ways to provide input to RESTful web services.
188.8.131.52 Using the Query String
A “GET” request will often pass input in the query string section of the URL. This example shows an input query sent in this way to the Open Movie Database API:
First, a FILENAME statement is used to set up a temporary file to hold the response from the web service.
Then, the query string is built. The Open Movie Database API expects a parameter detailing the search term(s) and an API key (apikey) as a minimum. We also specify a filter to results of type “movie” only. Each parameter is specified as a name=value pair, separated by an ampersand, in the following format:
The search term is URL encoded to avoid any issues with the interpretation of spaces using the URLENCODE function.
The ampersands are quoted using the macro quoting function NRSTR to prevent SAS from attempting to resolve them as macro variables and printing a WARNING to the log when it fails to do so.
The HTTP procedure is used to call the URL, with the query string appended. The OUT option is set to the “resp” fileref set earlier, the METHOD option set to “GET”.
The web service returns JSON formatted data, which is read using a LIBNAME statement using the JSON engine.
Figure 2 shows the output of the PRINT procedure.
Figure 2 – PRINT Procedure Output from The Open Movies Database
184.108.40.206 Using an Input Request
The following request does a POST to an open API set up to help when testing web service calls. We will send a new message in our input request, formatted as JSON data.
First, the required filename references are setup for the request, response and the output header. A data step with the FILE statement is used to create our input request; in this case some simple JSON.
The HTTP procedure calls the required URL for the endpoint, and the IN, OUT and HEADEROUT options are set to the filerefs. The METHOD option is set to “POST”.
The output header written to the “head_out” fileref is shown below.
There are several pieces of useful information in the header. Line 1 shows the HTTP return code for the request, in this case “201 created”, showing our post was successfully registered. The HTTP return code is the first thing to test in an error checking routine for a web service call.
The header also shows the format of the output that was sent. This information is held in the “Content- Type” field, and in this case is JSON formatted data in the UTF8 encoding.
The output from the service itself, written to the “resp_out” fileref, is shown below:
Creating Web Services in SAS®
3.1 The SAS BI Web Services Application
Included with SAS Integration Technologies, the SAS BI Web Services Application (SASBIWS) is a middle tier application that allows SAS Stored Processes to be called via SOAP and REST endpoints, effectively turning them into Web Services.
3.1.1 Hello World!
We can call the sample “Hello World!” stored process as an example of this concept, using the SOAP protocol. In this example the request is built and sent using the free program SoapUI.
The URL is built from the web application server root, the path to the SASBIWS SOAP endpoint (SASBIWS/services) and the metadata folder path to the stored process appended together:
In this example, the web application server URL is http://hostname:port/, the SOAP endpoint is “SASBIWS/services” and the default path to the “Hello World” sample stored process is “/Products/SAS Intelligence Platform/Samples/Sample: Hello World”. Note that any spaces and special characters are URL encoded.
For the SOAP endpoint, the WSDL can be accessed by appending “?wsdl” to the URL.
The sample request built automatically from the WSDL using the functionality provided by SoapUI is shown in Figure 3.
Figure 3 – Default Request Built from the “Hello World” Sample Stored Process
If we run this request, we get the response shown in Figure 4.
Figure 4 – Response from the “Hello World!” Stored Process Sample
The output of the “Hello World” stored process is a simple HTML page, streamed to the _WEBOUT fileref. In the response, SAS has returned this HTML, Base 64 encoded. If we decode this string we can see the HTML, shown in Figure 5.
Figure 5 – Decoding Base64 using SAS
This output is not very useful, but there are several ways we can write a stored process specifically with web services in mind.
3.1.2 A Better Example – Parameters
The SAS BI Web Services Application offers several mechanisms to call a single stored process. In this paper we will cover SOAP as well as RESTful calls using both XML and JSON.
Let’s create a better example, that takes some input and produces a readable output in the response. The following very simple SAS code takes a string passed as a macro variable and returns it as upper case:
We define the input and output parameters expected in the stored process definition. The “Parameters” tab of the properties window is shown in Figure 6
Figure 6 – The Parameters Tab of the Stored Process Properties
220.127.116.11 Calling as a SOAP Service
Using SoapUI, we can call the new “upcase” service. The WSDL is accessed as before, by appending the metadata path to the stored process to the SASBIWS/services/ URL, along with the “?wsdl” extension:
The generated request, with input provided, is shown in Figure 7.
Figure 7 – SOAP Request to the “upcase” Service
The response is shown in Figure 8.
Figure 8 – SOAP Response from the “upcase” Service
18.104.22.168 Calling as a RESTful Service Using XML
We can call the same service using the REST protocol and XML. The URL stub for XML calls to RESTful services is http://hostname:port/SASBIWS/rest/storedProcesses/.
The metadata path to the stored process is appended, as for SOAP, to become:
To make example calls to RESTful services a suitable REST client is required. The following screenshots use Postman, a free client at the time of writing.
The screenshot in Figure 9 shows a call to the upcase stored process made via the REST interface.
Figure 9 – RESTful Request to “upcase” Service Using XML
There are a few important settings:
- The HTTP header value for “Content Type” must be set to “application/xml”
- SAS uses two HTTP verbs for RESTful calls. Stored processes that require no input use GET, whilst POST is used to when parameters or stream input are required.
- The parameter must be provided matching the XML format shown in Figure 9. This can be derived from the equivalent SOAP request; remove all SOAP elements and references to the namespace (the part before the colon in opening and closing XML tags).
Alternatively, you can access output parameters directly, without the verbose XML structure, by appending the target resource to the URL in the format outputParameter/parameterName. For example:
Figure 10 shows a call made in this way to the upcase stored process. Note that only the value of the parameter is returned.
Figure 10 – Accessing Output Parameters Directly Using the REST Interface
22.214.171.124 Calling as a RESTful Service Using JSON
JSON is also supported as an output format. The JSON endpoint is constructed using the URL stub http://hostname:port/SASBIWS/json/storedProcesses/.
The metadata path to the stored process is appended as for SOAP and RESTful XML calls. This makes the URL for our sample process:
The screenshot in Figure 11 shows a call to the upcase stored process, using the JSON REST interface.
Figure 11 – Call to the “upcase” Service Using JSON and the REST Interface
- The Content-Type HTTP header must be set to application/x-www-form-urlencoded
- Input parameters can be provided in the body as name value pairs, or passed via the query string (appended to the URL)
- The HTTP verb/method must be set to POST if input is required, GET if not It is not possible to
access output parameters directly using the JSON interface.
3.1.3 Using Tables
As well as parameters, tables can be passed to web services. Let’s define a new example, the “contents” service. The SAS code for the service is shown below:
A XMLv2 libname engine library is assigned, reading from the “in_xml” fileref. The CONTENTS procedure is run on the “heros” table read from this libname, and an output data set is created. The output table is written back to an XML libname using a data step, referencing the “out_xml” fileref.
The stored process properties “Data” tab is shown in Figure 12. The input and output filerefs are defined to correspond to those used in the code. Both are set as type “XML Data Source”.
Figure 12 – Properties of the “contents” Stored Process
Note that the code does not explicitly create the filerefs; there are no FILENAME statements. The references are assigned automatically if referred to in the code.
The request format is slightly different when providing tables as input. A valid RESTful request for the “contents” service is shown below:
As when using input parameters, you can shortcut the request creation process by generating a SOAP request automatically from the WSDL using a tool such as SoapUI, and then modifying it for a RESTful call.
The response to this request is shown as a screenshot in Figure 13.
Figure 13 – Response from the “contents” Service
More complicated input and output XML can be read or generated using SAS XML maps. It is important to note that the output written to a fileref defined as an “XML Data Target” in the stored process properties must be valid XML, however it is generated, otherwise an error is returned when the service is called.
As is the case with parameters, it is possible to access the output structure directly (that is, only the output written to the fileref, without the verbose response tags around it) by altering the endpoint that is called. Data targets are accessed by appending “dataTarget/target_fileref” to the URL. The URL to access the “out_xml” fileref of the “contents” service becomes:
As example of the response format is shown in Figure 14.
Figure 14 – Accessing the Data Target Directly
3.1.4 Accessing Binary Output
SAS can produce a variety of binary output (PDF files, images, etc.) and these can also be returned from a web service. Let’s set up a simple example. The SAS code below forms the basis for the “binary” stored process:
An ODS statement opens an PDF ODS destination, with the body set to the “out_file” fileref. The PRINT procedure produces a simple listing, the two-level name of the data set to print is provided as a macro variable “libname_dataset”.
The stored process properties “Parameters” tab in metadata is shown in Figure 15, the “Data” tab in Figure 16.
Figure 15 – Parameters Tab of the “binary” Stored Process
Figure 16 – Data Tab of the “binary” Stored Process
A single input parameter is defined for the macro variable “libname_dataset”, along with a single data target, “out_file”, mapped to the fileref used in the code, and set as type “Generic Data Target”.
The RESTful request is shown below, passing the value “sashelp.class” as the value for the input parameter.
Calling the endpoint http://hostname:port/SASBIWS/rest/storedProcesses/Shared%Data/Stored%20Processes/binary gives the following response (note that the “value” has been truncated in order to fit the page):
The “out_file” in the response contains the PDF output, Base64 encoded to plain text. This can be decoded using a Base64 decoder to obtain the binary file.
The file can be accessed directly, like when accessing parameters and other data targets, by appending “dataTargets/fileref” OR “streams/fileref” to the URL. The endpoint for this example becomes:
The resulting behavior depends largely on the client you are using. For an ODS output, SAS sets the appropriate Content Type HTTP header which will allow most clients to prompt you to download the file or open it with an appropriate application.
For files not generated using ODS (read in with a binary FILENAME statement, for example) then it is not possible to set the Content Type header to match the file type from SAS.
This could cause a problem if calling the services from a client such as Postman but does not cause an issue for most programming languages that can write a binary file stream to disk. SAS is such a language.
Below is sample code for another stored process, “graph”, that reads a PNG file from the filesystem and returns it to the fileref “out_file”:
The stored process metadata is set up as for the “binary” service. SAS code used to call the “graph” service is shown below:
The HTTP procedure is used, as in the example on page 2. The out option is set to the fileref “out”, and the endpoint is called using the “get” HTTP method. This results in the binary file returned from the web service being written to the fileref.
The Future of Web Services and Web
SAS’ commitment to the web services ecosystem that has been explored in this paper has been underlined by the release of SAS Viya.
Viya presents a full RESTful API for executing CAS actions (loading data, perform analytics etc.), controlling sessions and monitoring the state of the system.
These are the building blocks to fully integrate SAS capabilities with any other language or system that has an HTTP library, which is just about anything!
Web service-based API’s are rapidly increasing in popularity; this trend is set to continue.
SAS is well placed to take advantage of the data and integration opportunities this provides with the HTTP and SOAP procedures, and to take part in it by publishing Stored Processes as web services through the SAS BI Web Services application.
SAS Viya builds on this with a full REST API that opens up SAS capabilities to a vast array of third-party languages and platforms.
World Wide Web Consortium. (2004). Web Services Glossary.
Retrieved from https://www.w3.org/TR/2004/NOTE-ws-gloss-20040211/#webservice
- Base SAS® Procedures Guide
- SAS® 9.4 BI Web Services: Developer’s Guide
- CAS REST API