Macros for SAS Application Developers
https://github.com/sasjs/core
ms_runstp.sas
Go to the documentation of this file.
1 /**
2  @file
3  @brief Executes a SASjs Server Stored Program
4  @details Runs a Stored Program (using POST method) and extracts the webout and
5  log from the response JSON.
6 
7  Example:
8 
9  %ms_runstp(/some/stored/program
10  ,debug=131
11  ,outref=weboot
12  )
13 
14  @param [in] pgm The full path to the Stored Program in SASjs Drive (_program
15  parameter)
16  @param [in] debug= (131) The value to supply to the _debug URL parameter
17  @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
18  @param [in] inputparams=(_null_) A dataset containing name/value pairs in the
19  following format:
20  |name:$32|value:$10000|
21  |---|---|
22  |stpmacname|some value|
23  |mustbevalidname|can be anything, oops, %abort!!|
24  @param [in] inputfiles= (_null_) A dataset containing fileref/name/filename in
25  the following format:
26  |fileref:$8|name:$32|filename:$256|
27  |---|---|--|
28  |someref|some_name|some_filename.xls|
29  |fref2|another_file|zyx_v2.csv|
30 
31  @param [out] outref= (outweb) The output fileref to contain the response JSON
32  (will be created using temp engine)
33  @param [out] outlogds= (_null_) Set to the name of a dataset to contain the
34  log. Table format:
35  |line:$2000|
36  |---|
37  |log line 1|
38  |log line 2|
39 
40  <h4> SAS Macros </h4>
41  @li mf_getuniquefileref.sas
42  @li mf_getuniquename.sas
43  @li mp_abort.sas
44  @li mp_chop.sas
45 
46 **/
47 
48 %macro ms_runstp(pgm
49  ,debug=131
50  ,inputparams=_null_
51  ,inputfiles=_null_
52  ,outref=outweb
53  ,outlogds=_null_
54  ,mdebug=0
55  );
56 %local dbg mainref authref boundary;
57 %let mainref=%mf_getuniquefileref();
58 %let authref=%mf_getuniquefileref();
59 %let boundary=%mf_getuniquename();
60 %if &inputparams=0 %then %let inputparams=_null_;
61 
62 %if &mdebug=1 %then %do;
63  %put &sysmacroname entry vars:;
64  %put _local_;
65 %end;
66 %else %let dbg=*;
67 
68 
69 %mp_abort(iftrue=("&pgm"="")
70  ,mac=&sysmacroname
71  ,msg=%str(Program not provided)
72 )
73 
74 /* avoid sending bom marker to API */
75 %local optval;
76 %let optval=%sysfunc(getoption(bomfile));
77 options nobomfile;
78 
79 /* add params */
80 data _null_;
81  file &mainref termstr=crlf lrecl=32767 mod;
82  length line $1000 name $32 value $32767;
83  if _n_=1 then call missing(of _all_);
84  set &inputparams;
85  put "--&boundary";
86  line=cats('Content-Disposition: form-data; name="',name,'"');
87  put line;
88  put ;
89  put value;
90 run;
91 
92 /* parse input file list */
93 %local webcount;
94 %let webcount=0;
95 data _null_;
96  set &inputfiles end=last;
97  length fileref $8 name $32 filename $256;
98  call symputx(cats('webref',_n_),fileref,'l');
99  call symputx(cats('webname',_n_),name,'l');
100  call symputx(cats('webfilename',_n_),filename,'l');
101  if last then do;
102  call symputx('webcount',_n_);
103  call missing(of _all_);
104  end;
105 run;
106 
107 /* write out the input files */
108 %local i;
109 %do i=1 %to &webcount;
110  data _null_;
111  file &mainref termstr=crlf lrecl=32767 mod;
112  infile &&webref&i lrecl=32767;
113  if _n_ = 1 then do;
114  length line $32767;
115  line=cats(
116  'Content-Disposition: form-data; name="'
117  ,"&&webname&i"
118  ,'"; filename="'
119  ,"&&webfilename&i"
120  ,'"'
121  );
122  put "--&boundary";
123  put line;
124  put "Content-Type: text/plain";
125  put ;
126  end;
127  input;
128  put _infile_; /* add the actual file to be sent */
129  run;
130 %end;
131 
132 data _null_;
133  file &mainref termstr=crlf mod;
134  put "--&boundary--";
135 run;
136 
137 data _null_;
138  file &authref lrecl=1000;
139  infile "&_sasjs_tokenfile" lrecl=1000;
140  input;
141  if _n_=1 then put "Content-Type: multipart/form-data; boundary=&boundary";
142  put _infile_;
143 run;
144 
145 %if &mdebug=1 %then %do;
146  data _null_;
147  infile &authref;
148  input;
149  put _infile_;
150  data _null_;
151  infile &mainref;
152  input;
153  put _infile_;
154  run;
155 %end;
156 
157 %local resp_path;
158 %let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
159 filename &outref "&resp_path" lrecl=32767;
160 
161 /* prepare request*/
162 proc http method='POST' headerin=&authref in=&mainref out=&outref
163  url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
164 %if &mdebug=1 %then %do;
165  debug level=2;
166 %end;
167 run;
168 
169 %if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
170 or &mdebug=1
171 %then %do;
172  data _null_;infile &outref;input;putlog _infile_;run;
173 %end;
174 %mp_abort(
175  iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
176  ,mac=&sysmacroname
177  ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
178 )
179 
180 /* reset options */
181 options &optval;
182 
183 %if &outlogds ne _null_ or &mdebug=1 %then %do;
184  %local matchstr chopout;
185  %let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
186  %let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
187 
188  %mp_chop("&resp_path"
189  ,matchvar=matchstr
190  ,keep=LAST
191  ,matchpoint=END
192  ,outfile="&chopout"
193  ,mdebug=&mdebug
194  )
195 
196  data &outlogds;
197  infile "&chopout" lrecl=2000;
198  length line $2000;
199  line=_infile_;
200  %if &mdebug=1 %then %do;
201  putlog line=;
202  %end;
203  run;
204 %end;
205 
206 %if &mdebug=1 %then %do;
207  %put &sysmacroname exit vars:;
208  %put _local_;
209 %end;
210 %else %do;
211  /* clear refs */
212  filename &authref;
213  filename &mainref;
214 %end;
215 %mend ms_runstp;