BookmarkSubscribeRSS Feed
askojuvonen1
SAS Employee

I hear quite often nowadays this question: how do I run my SAS (Viya) programs from outside using REST APIs?  

 

There is an excellent Github repository which addresses this question, with several practical code examples: https://github.com/sassoftware/rest-api-use-cases .

 

By following these examples, I tested SAS job execution from Python client. My example SAS program produces some summary statistics and a line graph from SASHELP.AIR dataset, which is filtered by two macro variables.

 

 

/* Create dataset */
proc sql; create table air_subset as select * from sashelp.air where date between "&startdate"d and "&enddate"d; quit; ods graphics / reset width=6.4in height=4.8in imagemap; /* Summary statistics */
proc means data=WORK.AIR_SUBSET chartype mean std min max median n vardef=df qmethod=os; var AIR; run; /* Histogram plot */
proc univariate data=WORK.AIR_SUBSET vardef=df noprint; var AIR; histogram AIR; run; proc sort data=WORK.AIR_SUBSET out=_SeriesPlotTaskData; by DATE; run; /* Line graph*/
proc sgplot data=_SeriesPlotTaskData; series x=DATE y=AIR /; xaxis grid; yaxis grid; run; ods graphics / reset; proc datasets library=WORK noprint; delete _SeriesPlotTaskData; run;

I saved the sas-program as plot_air.sas and created a job definition of it. I placed the job definition in Public-folder.

 

askojuvonen1_0-1670516509106.png

 

 

Our SAS part of the experiment is now ready!

 

Let’s do the REST call in Python next. 

 

First thing to do is the authentication. For my testing purposes, I authenticate with user id and password. There are more secure ways to do the authentication: you should follow the security policies of your organization.

 

Note that steps 1 and 2 are for registrating the client, and they are not needed to run after initial registration.

 

import requests as request
import time

# To get the client_token, you need to run this command in Viya server: 
# kubectl -n sse get secret sas-consul-client -o jsonpath="{.data.CONSUL_TOKEN}" | echo "$(base64 -d)"

sasserver = "https://myviyaserver.sas.com"
client_token = "<client token from kubectl command above>"
username =  “myusername”
password = “mypassword”
client_id = "myclient"
client_secret = "mysecret"
# Step 1 : Get the client access token url = sasserver+"/SASLogon/oauth/clients/consul?callback=false&serviceId=" + client_id payload = {} headers = { "X-Consul-Token": client_token } response = request.request("POST", url, headers=headers, data = payload, verify=False).json() client_access_token = response["access_token"]
# Step 2 : Register the client url = sasserver+"/SASLogon/oauth/clients" payload = {"client_id": client_id, "client_secret": client_secret, "scope": ["*"], "resource_ids": "none", "authorities": ["uaa.none"], "authorized_grant_types": ["password"], "access_token_validity": 36000} headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + client_access_token } response = request.request("POST", url, headers = headers, json = payload, verify=False).json() # Step 3 : Get the access token url = sasserver + "/SASLogon/oauth/token" data = { 'grant_type': 'password', 'username': username, 'password': password } headers = {'Accept': 'application/json'} response = request.post(url, headers=headers, data=data, auth=(client_id, client_secret), verify=False).json() access_token = response["access_token"]

 

Step 4 makes the REST API call to the desired job (/Public/plot_air). Note that the macro variables (startdate, enddate) which filter the AIR-dataset  in plot_air.sas are set as parameters in URL.  

 

# Step 4 : Call the SAS job plot_air with parameters startdate and enddate
job_url = sasserver+"/SASJobExecution/?_program=/Public/plot_air&startdate=1JAN1950&enddate=31DEC1959"
url = job_url + '&_action=json&_resultfile=*&_omittextlog=false'

headers = {
    'Authorization': 'bearer ' + access_token,
    'Content-Type': 'application/vnd.sas.job.execution.job.request',
    'Accept': 'application/vnd.sas.job.execution.job'
}

r = request.post(url, headers=headers, verify=False).json()

 

In Step 5, the result URLs are read from the HTTP response. log_uri contains the URL into SAS log, and output_uri  into SAS output.

 

# Step 5 : get the SAS log and SAS output URLs
log_uri = sasserver + r['items'][1]['href']
output_uri = sasserver + r['items'][2]['href']
print(log_uri)
print(output_uri)

 

In the last step, the HTML result is written into local file.

 

# Step 6 : write the SAS output html-file into local folder

output_str = request.get(output_uri, headers=headers, verify=False).text
filename = "c:\\temp\\Output_"+time.strftime("%Y%m%d-%H%M%S")+".html"
with open(filename, "w") as output_html:
    output_html.write(output_str)

 

And this is how the result HTML looks!

 

askojuvonen1_0-1670518011444.png