Need To Replicate a cURL call With CFHTTP
Copy link to clipboard
Copied
Hello:
I need to replicate the following cURL call, which uses a multipart/form-data header and form fields:
curl -L -R POST "https://api.XXXXXXXX.com/api/v1/academic_success/sync/enrollment" \
-H "Authorization: Bearer <access_token>" \ # Generated OAuth2 token request
-H "Content-Type: multipart/form-data" \
-F "input_type=CSV" \
-F "input_data=@enrollment_upload.csv" \ # Path to CSV file. Include '@' before path.
-F "dry_run=false" \ # Set to true when testing
-F 'drop_not_passed_enrollments=true' \ # only enabled when dry_run = false
CFHTTP does not allow specifying form fields for multi-part data. I assume I'd have to code a header that included the form fields as part of the body along with the data, but am unclear on how to do this. We are currently production with CF 2018.
Thanks.
Gerry, Pace University
Copy link to clipboard
Copied
Could you please share the cfhttp code that you used.
Copy link to clipboard
Copied
BKBK:
Thank you for getting back to me. The code is below, I assume it needs to have request headers for the form variables added, along with multi part header commented out in the CFHTTPPARAM. Just not sure of the exact specification for the headers and their order, I assume the form variables would come before the data (CSV) being sent.
Gerry, Pace University
<CFSCRIPT>
REQUEST.ApiEnrollment = "http://httpbin.org/post"
// The contents for the BODY, but need to include headers for the form variable
REQUEST.LoadBody = "" ;
REQUEST.LoadBody = REQUEST.LoadBody & "input_type=CSV&" ;
REQUEST.LoadBody = REQUEST.LoadBody & "dry_run=true&" ;
REQUEST.LoadBody = REQUEST.LoadBody & "input_data=" & REQUEST.DataBlob ;
REQUEST.LoadBody = UrlEncodedFormat( REQUEST.LoadBody ) ;
CFHttp( Url="#REQUEST.ApiEnrollment#" , Method="POST" , ThrowOnError="YES" , MultiPart="YES" , MultiPartType="RELATED" , TimeOut="450" )
{
CFHttpParam( Type="Header" , Name="Authorization" , Value="#REQUEST.Token#" ) ;
CFHttpParam( Type="Header" , Name="X-TW-PersonId" , Value="#REQUEST.XTWPersonId#" ) ;
// CFHttpParam( Type="Header" , Name="Content-Type:" , Value="multipart/form-data" ) ;
// CFHttpParam( Type="FormField" , Name="input_type" , Value="CSV" ) ;
// CFHttpParam( Type="FormField" , Name="input_data" , Value="#REQUEST.CsvName#" ) ;
// CFHttpParam( Type="FormField" , Name="dry_run" , Value="true" ) ;
CFHttpParam( Type="Body" , Value="#REQUEST.LoadBody#" ) ;
}
WriteOutput( '<br/>***** PROGRAM: Send Student Data</br></br>' ) ;
WriteOutput( 'Return Code Is ' & CFHTTP.StatusCode ) ;
WriteOutput('<br/><br/>') ;
Returned = deserializeJSON( CFHttp.FileContent ) ;
WriteDump( Var="#Returned#" , Label="Returned Variables" ) ;
</CFSCRIPT>
Copy link to clipboard
Copied
The instructions at http://httpbin.org suggest you might be able to send JSON data. If so, then you could do it simply, without any need for multipart/form-data.
Try something like:
REQUEST.DataBlob=fileread("full_path_to_CSV_file");
REQUEST.ApiEnrollment="API_URL";
REQUEST.LoadBody=structNew();
REQUEST.LoadBody.input_type="CSV";
REQUEST.LoadBody.dry_run="true";
REQUEST.LoadBody.input_data=REQUEST.DataBlob;
CFHttp( Url="#REQUEST.ApiEnrollment#" , Method="POST" , ThrowOnError="YES", TimeOut="450" )
{
CFHttpParam( Type="Header" , Name="Authorization" , Value="#REQUEST.Token#" );
CFHttpParam( Type="Header" , Name="X-TW-PersonId" , Value="#REQUEST.XTWPersonId#" );
Cfhttpparam( Type="Header" , Name="Content-Type" , value="application/json");
CFHttpParam( Type="Body" , Value="#serializeJson(REQUEST.LoadBody)#" ) ;
}
Copy link to clipboard
Copied
BKBK:
First, apologies on the delayed response, I'm severely slammed on time with another project. I hope that httpbin.org are correct ! I will given it a try as soon as I can, probably this evening.
Thank you again for the assistance -- it is much appreciated. Have a great day !
Gerry, Pace University
Copy link to clipboard
Copied
No worries, Gerry.
Wishing you lots of fun with the projects!
Copy link to clipboard
Copied
BKBK: let me first apologize for not responding sooner. I just got a chance a little while ago to run your code, it failed though it mentioned the request was well formed (see message below). The field that the says was missing, you did have in code. It appears that the site couldn't parse the payload correctly. I get the feeling that I will need do boundary headers for the form fields manually and add them to body to get it to be consumed properly. Again, apologies for the very late response, I am very appreciative of your assisting us in this matter. Gerry, Pace University
Return Code Is 422 UNPROCESSABLE ENTITY
Returned Variables - struct
message | The request was well-formed but was unable to be followed due to semantic errors. | ||||
messages | Returned Variables - struct
| ||||
status | 422 |
Copy link to clipboard
Copied
The error message suggests that the API understands the request, but perhaps requires a slightly different representation. So what happens when you send a JSON rather than a JSON string. That is, test with the following line
CFHttpParam( Type="Body" , Value=#serializeJson(REQUEST.LoadBody)# ) ;
Copy link to clipboard
Copied
BKBK: I did, I used the exact code you sent, with the one exception of course of it going to the actual vendor site. Below is the code that was run. Gerry
<CFSCRIPT>
// Code From BKBK
//REQUEST.ApiEnrollment = "http://httpbin.org/post"
//REQUEST.DataBlob=fileread("full_path_to_CSV_file");
//REQUEST.ApiEnrollment="API_URL";
REQUEST.LoadBody=structNew();
REQUEST.LoadBody.input_type="CSV";
REQUEST.LoadBody.dry_run="true";
REQUEST.LoadBody.input_data=REQUEST.DataBlob;
CFHttp( Url="#REQUEST.ApiEnrollment#" , Method="POST" , ThrowOnError="YES", TimeOut="450" )
{
CFHttpParam( Type="Header" , Name="Authorization" , Value="#REQUEST.Token#" );
CFHttpParam( Type="Header" , Name="X-TW-PersonId" , Value="#REQUEST.XTWPersonId#" );
Cfhttpparam( Type="Header" , Name="Content-Type" , value="application/json");
CFHttpParam( Type="Body" , Value="#serializeJson(REQUEST.LoadBody)#" ) ;
}
WriteOutput( '<br/>***** PROGRAM: Send Student Data</br></br>' ) ;
WriteOutput( 'Return Code Is ' & CFHTTP.StatusCode ) ;
WriteOutput('<br/><br/>') ;
Returned = deserializeJSON( CFHttp.FileContent ) ;
WriteDump( Var="#Returned#" , Label="Returned Variables" ) ;
</CFSCRIPT>
Copy link to clipboard
Copied
And did that work?
Copy link to clipboard
Copied
BKBK: Will update tomorrow with code, and form vars setup boundary separaters. Thanks for checking back. Gerry
Copy link to clipboard
Copied
BKBK:
Attached is the latest code version with everything stuffed into the body. Returns a 200 ok from the http://httpbin.org/post, it did not find anything with the boundary separator coding, but that is not unusal with that site. I won't be able to run it against the vendor test till next Monday. The code file is attached. Have a great weekend. Gerry

