+ Start a Discussion
paul-lmipaul-lmi 

More code samples on http, httprequest, and httpresponse

The documentation only really has a code sample for a simple GET request.  This may be fine for some, but I'm lost on how to properly set up a standard POST request, specifically, setting header and body info.
Ron HessRon Hess
Hi Paul, timely request, i've recently been putting data with httprequest.  Here is the code to construct a PUT, add body, headers and send it.

Code:
 /* 
  * main callout method
  */
 public void makeRequest(string method) {
  HttpRequest req = new HttpRequest(); 
  
  req.setMethod(method);
  if(method == 'PUT') { 
   if ( ! headers.containsKey('content-type') ) { 
    system.debug('ERROR: missing content-type in PUT request'); return; 
   } 
   system.debug('content-type is >' +headers.get('content-type'));
   req.setHeader('content-type', headers.get('content-type') );
   
   if ( body == null ) { 
    system.debug( 'body must not be null in PUT'); return; 
   }
   req.setBody(body); 
   req.setCompressed(true); // otherwise we hit a limit of 32000
  }
  System.assert(this.BUCKET_NAME != null,'Missing Bucket name :setBucket(name)');
  req.setEndpoint( this.serviceEndPoint + this.BUCKET_NAME +'/' + this.key);
  setDateString();
  req.setHeader('Date',getDateString()); 
  setAuthHeader(req);  
  if ( ! headers.isEmpty() ) { 
   for(string k:headers.keySet() ) { 
    system.debug('setheader ' + k + ' => ' +headers.get(k) ); 
    req.setHeader(k, headers.get(k) ); 
   }
  }
  //this.res = null;
  Http http = new Http();
  try {
   system.debug(req);
   res = http.send(req); 
   if (debug > 1) {
    system.debug(res.toString());
    //System.debug('STATUS:'+res.getStatus());System.debug('STATUS_CODE:'+res.getStatusCode());
    System.debug('BODY: '+res.getBody());
   }
  } catch(System.CalloutException e) {
   if (res.getStatus()=='OK') { 
    system.debug(res.toString()); // for some reason HEAD ends up here
   } else { 
    System.debug('ERROR: '+ e);
    system.debug(res.toString());
   }
  }
  body = null; // don't reuse this
  headers.clear(); 
 }

a few more helpers
Code:
 public void setDateString() { 
  this.dateString = this.formatDateString(System.now());   
 }



 
Code:
 private void setAuthHeader(HTTPRequest req) {  
  string buf = make_canonicalBuffer(req.getMethod(),getDateString(),new string[]{}, req.getEndpoint());
  if(debug>2) system.debug ('>'+buf +'<');
  string signature  = make_sig(buf);  
  req.setHeader('authorization','AWS '+AWS_ACCESS_KEY_ID+':'+signature);
 }
  

 

Now, this code is taken from a larger project, but you can see how easy it is to set a header and body on a PUT request.

hope this helps.  
paul-lmipaul-lmi
so i take it that your object 'headers' is a Map?  just trying to wrap my head around that.  :)  thanks!

by the way, where would you recommend i submit this class when i'm done?  I'm building a class to allow integration with defensio.com's spam filtering/checking API, so I'm sure it'll help quite a few that want to add some data checks to their triggers before actually inserting data.
Ron HessRon Hess
Yes, it's a map, looks like this

    private Map<String,String> headers = new Map<String, String>{};

    public void setHeaders(Map<String, String> h) {headers = h.clone();}



feel free to contribute to a force.code.share project, if you are interested, send me a note and I can add you as a contributor.

This is the project that i've begun to build:
http://code.google.com/p/visualforce-components/

click join project and we should be able to add you.


On your suggested use, you cannot make callouts from a trigger, the issue is database locking, in a trigger there is a transaction inflight. This is not compatable with a callout, which has a timeout of 10 seconds.  Delaying a save or update by 10 seconds is no way to run a database.

You can create a simple button that makes the callout and marks the offending records as spam, and deletes them or moves them into a queue.

I would love to look over your code when it's running.


paul-lmipaul-lmi
heh, nevermind, i answered my own question.  it's a map.  thank you SO much.  once i'm done with this, it'll save multiple people hours of work a day.

you think they'd let me take a vacation after....:)
paul-lmipaul-lmi
alrighty, last question hopefully.

so when i build this request as a POST request instead of a GET, am I just building the full URL string as the endpoint?

example: (the global__c stuff is may way of storing global variables in SFDC itself without hard coding them)
Code:
  List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
  string apikey = apikeyrequest[0].Value__c;
  List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
  string ownerurl = ownerurlrequest[0].Value__c;
  date commentDate = system.today();
  string commentAuthor = sentfromname;
  string commentAuthorEmail = sentfromemail;
  string commentContent = bodytext;
  string apiurl = 'http://defensio.com/app/1.2/';
  string action = 'audit-comment/';
  string responsetype = 'yaml';
  string endpoint = apiurl + action + apikey + '.' + responsetype + '—owner-url=' + ownerurl + '&article-date=' + commentDate + '&comment-author=' + commentAuthor + '&comment-content=' + commentContent + '&user-ip=64.25.87.42' + '&comment-author-email=' + commentauthoremail;
  system.debug(endpoint);

 and then:

Code:
  //do the request
  req.setEndpoint(endpoint);
  Map<string, string> headers = new Map<string, string>();
  headers.put('content-length', '0');
  req.setHeader('content-length', headers.get('content-length'));
  req.setMethod('POST');
  http http = new http();
  httpresponse auditCommentResponse = http.send(req);
  string response = auditCommentResponse.getBody();
  system.debug('---Response: ' + response + '---');

 I'm sure that's wrong or at least there's a better way I'm not aware of.  Forgive my newness, I'm a networking guy, not a web dev, so I'm not sure how I'm supposed to pass the params to the endpoint as a POST.  Are the parameters supposed to be part of the body itself?  In my reading it states that POST variables are supposed to be sent as part of the request, and are seperated from the headers by a blank line.

Once we're good here, I think I'll write a pretty example of POST and have you guys add it to the example in the Apex Developer's Guide.

Ron HessRon Hess
in a post, you can construct the request both ways if i recall.

placing the name=values on the url, or in the body (newline seperated?)

so, normal endpoint, then something like

req.setBody("myparam=myValue1\nmyparm2=myvalue2");


you may find that when you write a testMethod for this, you are not able to make the actual callout (from a testMethod), this is a limitation.

instead, i normaly write a simple (public static) wrapper method that i can call from the execute Anonomous window to test the callouts i've written.

paul-lmipaul-lmi
i just run it in the debug part of the System Log popup window.  i'll give it a shot!
paul-lmipaul-lmi
I figured it out.

to set POST parameters, you set body equal to:

param1=value&param2=value&param3=value

i had to dissect an HTML form POST with Wireshark to figure that one out, lol
trublutrublu

Hi all/paul-lmi,

 

I tried to set the body as a a "param1=value&param2=value&param3=value" string, an html form, and a full html, but the system receiving my http post is still not recognizing my post.

 

Could anyone please help?  Below is my code. Thank you very much!!! I am totally stuck....

===============================
       String theMessage = 'userid='+'xyz.test@xyz.com'+'&password='+ 'test123' + '&SAMLRequest=' + request;

      

       HttpRequest req = new HttpRequest();
       req.setEndpoint('http://xyz.com/myserver/authorization/AuthenticationServlet');
       req.setMethod('POST');
       req.setHeader('Content-Type', 'text/html');
       req.setBody(theMessage);
       

       Http h = new Http();       
       HTTPResponse res;
       res = h.send(req);

SuperfellSuperfell

To post a form, you need to use the correct content-type of application/x-www-form-urlencoded