Macros for SAS Application Developers
https://github.com/sasjs/core
mv_getjobresult.sas
Go to the documentation of this file.
1 /**
2  @file
3  @brief Extract the result from a completed SAS Viya Job
4  @details Extracts result from a Viya job and writes it out to a fileref
5  and/or a JSON-engine library.
6 
7  To query the job, you need the URI. Sample code for achieving this
8  is provided below.
9 
10  ## Example
11 
12  First, compile the macros:
13 
14  filename mc url
15  "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
16  %inc mc;
17 
18  Next, create a job (in this case, a web service):
19 
20  filename ft15f001 temp;
21  parmcards4;
22  data test;
23  rand=ranuni(0)*1000;
24  do x=1 to rand;
25  y=rand*4;
26  output;
27  end;
28  run;
29  proc sort data=&syslast
30  by descending y;
31  run;
32  %webout(OPEN)
33  %webout(OBJ, test)
34  %webout(CLOSE)
35  ;;;;
36  %mv_createwebservice(path=/Public/temp,name=demo)
37 
38  Execute it:
39 
40  %mv_jobexecute(path=/Public/temp
41  ,name=demo
42  ,outds=work.info
43  )
44 
45  Wait for it to finish, and grab the uri:
46 
47  data _null_;
48  set work.info;
49  if method='GET' and rel='self';
50  call symputx('uri',uri);
51  run;
52 
53  Finally, fetch the result (In this case, WEBOUT):
54 
55  %mv_getjobresult(uri=&uri,result=WEBOUT_JSON,outref=myweb,outlib=myweblib)
56 
57 
58  @param [in] access_token_var= The global macro variable containing the access
59  token
60  @param [in] mdebug= set to 1 to enable DEBUG messages
61  @param [in] grant_type= valid values:
62  @li password
63  @li authorization_code
64  @li detect - will check if access_token exists, if not will use sas_services
65  if a SASStudioV session else authorization_code. Default option.
66  @li sas_services - will use oauth_bearer=sas_services.
67  @param [in] uri= The uri of the running job for which to fetch the status,
68  in the format `/jobExecution/jobs/$UUID` (unquoted).
69 
70  @param [out] result= (WEBOUT_JSON) The result type to capture. Resolves
71  to "_[column name]" from the results table when parsed with the JSON libname
72  engine. Example values:
73  @li WEBOUT_JSON
74  @li WEBOUT_TXT
75 
76  @param [out] outref= (0) The output fileref to which to write the results
77  @param [out] outlib= (0) The output library to which to assign the results
78  (assumes the data is in JSON format)
79 
80 
81  @version VIYA V.03.05
82  @author Allan Bowe, source: https://github.com/sasjs/core
83 
84  <h4> SAS Macros </h4>
85  @li mp_abort.sas
86  @li mp_binarycopy.sas
87  @li mf_getplatform.sas
88  @li mf_existfileref.sas
89 
90 **/
91 
92 %macro mv_getjobresult(uri=0
93  ,access_token_var=ACCESS_TOKEN
94  ,grant_type=sas_services
95  ,mdebug=0
96  ,result=WEBOUT_JSON
97  ,outref=0
98  ,outlib=0
99  );
100 %local dbg;
101 %if &mdebug=1 %then %do;
102  %put &sysmacroname entry vars:;
103  %put _local_;
104 %end;
105 %else %let dbg=*;
106 
107 %local oauth_bearer;
108 %if &grant_type=detect %then %do;
109  %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
110  %else %let grant_type=sas_services;
111 %end;
112 %if &grant_type=sas_services %then %do;
113  %let oauth_bearer=oauth_bearer=sas_services;
114  %let &access_token_var=;
115 %end;
116 
117 %mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
118  and &grant_type ne sas_services
119  )
120  ,mac=&sysmacroname
121  ,msg=%str(Invalid value for grant_type: &grant_type)
122 )
123 
124 
125 /* validation in datastep for better character safety */
126 %local errmsg errflg;
127 data _null_;
128  uri=symget('uri');
129  if length(uri)<12 then do;
130  call symputx('errflg',1);
131  call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
132  end;
133  if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
134  call symputx('errflg',1);
135  call symputx('errmsg',
136  "URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
137  !!" but is actually like: &uri",'l');
138  end;
139 run;
140 
141 %mp_abort(iftrue=(&errflg=1)
142  ,mac=&sysmacroname
143  ,msg=%str(&errmsg)
144 )
145 
146 %if &outref ne 0 and %mf_existfileref(&outref) ne 1 %then %do;
147  filename &outref temp;
148 %end;
149 
150 options noquotelenmax;
151 %local base_uri; /* location of rest apis */
152 %let base_uri=%mf_getplatform(VIYARESTAPI);
153 
154 /* fetch job info */
155 %local fname1;
156 %let fname1=%mf_getuniquefileref();
157 proc http method='GET' out=&fname1 &oauth_bearer
158  url="&base_uri&uri";
159  headers "Accept"="application/json"
160  %if &grant_type=authorization_code %then %do;
161  "Authorization"="Bearer &&&access_token_var"
162  %end;
163  ;
164 run;
165 %if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
166 %do;
167  data _null_;infile &fname1;input;putlog _infile_;run;
168  %mp_abort(mac=&sysmacroname
169  ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
170  )
171 %end;
172 %if &mdebug=1 %then %do;
173  data _null_;
174  infile &fname1 lrecl=32767;
175  input;
176  putlog _infile_;
177  run;
178 %end;
179 
180 /* extract results link */
181 %local lib1 resuri;
182 %let lib1=%mf_getuniquelibref();
183 libname &lib1 JSON fileref=&fname1;
184 data _null_;
185  set &lib1..results;
186  call symputx('resuri',_&result,'l');
187  &dbg putlog "&sysmacroname results: " (_all_)(=);
188 run;
189 %mp_abort(iftrue=("&resuri"=".")
190  ,mac=&sysmacroname
191  ,msg=%str(Variable _&result did not exist in the response json)
192 )
193 
194 /* extract results */
195 %local fname2;
196 %let fname2=%mf_getuniquefileref();
197 proc http method='GET' out=&fname2 &oauth_bearer
198  url="&base_uri&resuri/content?limit=10000";
199  headers "Accept"="application/json"
200  %if &grant_type=authorization_code %then %do;
201  "Authorization"="Bearer &&&access_token_var"
202  %end;
203  ;
204 run;
205 %if &mdebug=1 %then %do;
206  /* send one char at a time as the json can be very wide */
207  data _null_;
208  infile &fname2 recfm=n;
209  input char $char1. ;
210  putlog char $char1. @;
211  run;
212 %end;
213 
214 %if &outref ne 0 %then %do;
215  filename &outref temp;
216  %mp_binarycopy(inref=&fname2,outref=&outref)
217 %end;
218 %if &outlib ne 0 %then %do;
219  libname &outlib JSON fileref=&fname2;
220 %end;
221 
222 %if &mdebug=0 %then %do;
223  filename &fname1 clear;
224  filename &fname2 clear;
225  libname &lib1 clear;
226 %end;
227 %else %do;
228  %put &sysmacroname exit vars:;
229  %put _local_;
230 %end;
231 
232 %mend mv_getjobresult;