Hi,
I'm try to send to an API a request (json content).
As the maximum number of element of each request is 100 (and my dataset may contain 5000 or more entries) i try to process over a batch of 10 elements (for testing).
I produce the code bellow who's working as expected if i didn't call the macro in the loop but print the content of my concatened_json variable.
But if i try to pass the json in the macro parameter i got an error like macro parameter contains syntax error.
In my mind the "best" way to achieve it is to create a temporary file, pass it to the macro to make the proc http query, reset the content of the file and process again... but i'm struggle to write it
/****** Update product with API PATCH Request *****/ %macro updateProduct(json_in); proc http method="PATCH" url="http://xxx/api/rest/v1/products" in=&json_in. out=resp; headers "Authorization" = "Bearer &token." "Content-Type"="application/vnd.akeneo.collection+json"; run; %mend; data _null_; set temp; array json_arr[100] $1000 _temporary_; /* Declare the variable to retain the concatenated JSON strings */ length concatenated_json $32767; /* Adjust the length as needed */ length json_in_str $32767; retain concatenated_json; json_in_str = '{"identifier":"' || compress(sku) || '","enabled":' || put(enabled, 1. -l) || ',"values":{'; json_arr[0] = ' "availibility_code":[{"scope":null,"locale":null,"data":"' || availibility_code || '"}],'; json_arr[1] = ' "allowed_cpy":[{"scope":null,"locale":null,"data":"' || compress(allowed_cpy) || '"}],'; json_arr[2] = ' "libelle":[{"scope":null,"locale":null,"data":"' || compbl(libelle) || '"}]'; do i = 1 to dim(json_arr); if not missing(json_arr[i]) then json_in_str = catx(' ', json_in_str, json_arr[i]); end; /* Finish building the JSON payload */ json_in_str = catx(' ', json_in_str, '}}'); concatenated_json = catx(' ', concatenated_json, json_in_str); /* Loop to print content every 10 iterations */ if mod(_N_, 10) = 0 then do; /*put concatenated_json;*/ call execute('%updateProduct(' || concatenated_json || ');'); concatenated_json =""; end; run;
any help is much appreciated.
Also open on suggestion / improvements as i starting with SAS and not a lot of experience...
Thanks
Write separate files. Then generate separate HTTP calls for each file.
So something like will make files with 10 records each and a dataset with a list of the file it made.
Just change the DO loop upperbound to use some number other than 10 per file.
%let path=%sysfunc(pathname(work));
data files ;
fileno+1;
length $8 inref outref $8 infile outfile $200;
inref=cats('in',fileno);
infile=cats("&path/in",fileno,".json");
rc1 = filename(inref,infile);
outref=cats('out',fileno);
outfile=cats("&path/out",fileno,".json");
rc2=filename(outref,outfile);
file json filevar=infile;
do n=1 to 10 until(eof);
set have end=eof;
/* stuff that writes the JSON lines text */
end;
keep fileno -- rc2;
run;
Then you can use that dataset with the list of files you created to make the PROC HTTP calls.
data _null_;
set files;
call execute(catx(' ','proc http method="PATCH"'
,'url="http://xxx/api/rest/v1/products"'
,'in=',inref
,'out=',outref
,';headers'
,'"Authorization" = "Bearer &token."'
,'"Content-Type"="application/vnd.akeneo.collection+json";'
,'run;'
));
run;
Look at the syntax for PROC HTTP. Doesn't it support passing the "IN" text via a FILE instead of trying to type it all into the code?
Yes I can send a file (that's my goal at the end).
For testing i updated the macro to display the file content.
%macro updateProduct(json_in);
data _null_;
infile json_in;
input;
*put "*******------******";
put "DEBUG: > " _infile_;
*put "*******------******";
run;
%mend;
data _null_;
set temp;
array json_arr[100] $1000 _temporary_;
/* Declare the variable to retain the concatenated JSON strings */
length concatenated_json $32767; /* Adjust the length as needed */
length json_in_str $32767;
retain concatenated_json;
filename payload temp;
*json_in_str = '{"identifier":"' || compress(sku) || '"}';
json_in_str = '{"identifier":"' || compress(sku) || '","enabled":' || put(enabled, 1. -l) || ',"values":{';
json_arr[2] = ' "code_mega":[{"scope":null,"locale":null,"data":"' || compress(code_mega) || '"}],';
json_arr[3] = ' "availibility_code":[{"scope":null,"locale":null,"data":"' || availibility_code || '"}],';
json_arr[4] = ' "allowed_cpy":[{"scope":null,"locale":null,"data":"' || compress(allowed_cpy) || '"}],';
json_arr[5] = ' "libelle_digis":[{"scope":null,"locale":null,"data":"' || compbl(libelle_digis) || '"}]';
do i = 1 to dim(json_arr);
if not missing(json_arr[i]) then
json_in_str = catx(' ', json_in_str, json_arr[i]);
end;
/* Finish building the JSON payload */
json_in_str = catx(' ', json_in_str, '}}');
concatenated_json = catx(' ', concatenated_json, json_in_str);
/* Loop to print content every 10 iterations */
if mod(_N_, 10) = 0 then do;
*put concatenated_json;
/* Step 1: Create and write to the temporary file */
file payload;
put concatenated_json;
/* Step 2: Pass the temporary file as a parameter to the macro */
call execute('%updateProduct(' || payload || ');');
/* Step 3: Clear the temporary file after the macro call */
filename payload clear;
*put '****';
concatenated_json ="";
end;
run;
Almost everything is working as expected, except the file is not "cleared" between each call to the macro.
for example in the first occurence i get 10 items on it, on the second one 20....
I was expecting the the clear will remove the content between each iteration but i should miss something...
Thanks
Write separate files. Then generate separate HTTP calls for each file.
So something like will make files with 10 records each and a dataset with a list of the file it made.
Just change the DO loop upperbound to use some number other than 10 per file.
%let path=%sysfunc(pathname(work));
data files ;
fileno+1;
length $8 inref outref $8 infile outfile $200;
inref=cats('in',fileno);
infile=cats("&path/in",fileno,".json");
rc1 = filename(inref,infile);
outref=cats('out',fileno);
outfile=cats("&path/out",fileno,".json");
rc2=filename(outref,outfile);
file json filevar=infile;
do n=1 to 10 until(eof);
set have end=eof;
/* stuff that writes the JSON lines text */
end;
keep fileno -- rc2;
run;
Then you can use that dataset with the list of files you created to make the PROC HTTP calls.
data _null_;
set files;
call execute(catx(' ','proc http method="PATCH"'
,'url="http://xxx/api/rest/v1/products"'
,'in=',inref
,'out=',outref
,';headers'
,'"Authorization" = "Bearer &token."'
,'"Content-Type"="application/vnd.akeneo.collection+json";'
,'run;'
));
run;
Many thanks! It did the work.
Just have to fine tune with some minor tuning but it's working as expected !!
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Select SAS Training centers are offering in-person courses. View upcoming courses for: