RESTful Web Service Callout using POST with Salesforce.com

March 16th, 2009

The addition of asynchronous Web service callouts to external services is a feature that developers have been requesting for quite awhile in Salesforce.com. Using the new @future annotation, your methods execute the callout when Salesforce.com has resources available. One of the great benefits is that it allows you to perform callouts during trigger executions.

One method of performing callouts is to import your WSDL and let Apex do all of the heavy lifting (WSDL2Apex). The major problem that I found is that Apex does not support RPC/encoded services at this time. Apex does support HTTP Service classes which will allow you to create RESTful services as an alternative. For more information and example code there is a great article entitled Apex Web Services and Callouts.

The HttpResponse class provides a simple GET example but it was hard to find any examples using POST so I thought I’d throw something together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
public class WebServiceCallout {
 
    @future (callout=true)
    public static void sendNotification(String name, String city) {
 
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
 
        req.setEndpoint('http://my-end-point.com/newCustomer');
        req.setMethod('POST');
        req.setBody('name='+EncodingUtil.urlEncode(name, 'UTF-8')+'&city='+EncodingUtil.urlEncode(city, 'UTF-8'));
        req.setCompressed(true); // otherwise we hit a limit of 32000
 
        try {
            res = http.send(req);
        } catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
            System.debug(res.toString());
        }
 
    }
 
    // run WebServiceCallout.testMe(); from Execute Anonymous to test
    public static testMethod void testMe() {
        WebServiceCallout.sendNotification('My Test Customer','My City');
    }
 
}

You can execute your callout in a trigger with the following example:

1
2
3
4
5
6
7
8
9
 
trigger AccountCallout on Account (after insert) {
 
	for (Account a : Trigger.new) {
		// make the asynchronous web service callout
		WebServiceCallout.sendNotification(a.Name, a.BillingCity);
	}
 
}

A couple of things to remember when using the future annotation:

  1. No more than 10 method calls per Apex invocation
  2. No more than 200 method calls per Salesforce license per 24 hours
  3. The parameters specified must be primitive dataypes, arrays of primitive datatypes, or collections of primitive datatypes.
  4. Methods with the future annotation cannot take sObjects or objects as arguments.
  5. Methods with the future annotation cannot be used in Visualforce controllers in either getMethodName or setMethodName methods, nor in the constructor.

Categories: Apex, Code Sample, Salesforce

Leave a comment

Comments Feed13 Comments

  1. Mike Simonds

    well I tried this out Jeff and it doesn’t work. Did you actually test this? I had another developer test this actual code and theirs also did not work.

    If you place the following code:

    <?php
    $temp = '

    '  . print_r($_POST, true) . '

    ‘;
    mail(‘me@email.com’, ‘APEX Data’, $temp);

    ?>

    and then test the code it does not show any of the data that you are sending via post, unlike the _$GET example

    I would like to see if you would look into this, this is a great tutorial!

    Thanks!!

    ~Mike

  2. jeffdonthemic

    Mike, what is the error you are getting?

  3. Mike Simonds

    Here are the two issues:

    1) webservicecallout: Methods defined as TestMethod do not support Web service callouts, test skipped – are not supported

    2) none of the post data is sent. The script is kicked off because I receive an empty email, but no post data

    Just thought that I would let you know

    Thanks

    ~Mike

  4. Mike Simonds

    Well I was messing around with it and removed the compression:

    req.setCompressed(true); // otherwise we hit a limit of 32000

    now it works !!

    But what can happen if we do not compress it

  5. Raghavender

    Hi,
    Thanks for the above article.Can you helo m eunderstand if we can make a https post from SFDC with an Example.
    Thanks.

    Raghu

  6. Phillip

    How do I actually test this. I’m getting the following exception:

    15:22:57.270|FATAL_ERROR|System.TypeException: Methods defined as TestMethod do not support Web service callouts, test skipped

  7. Vikram nanduri

    Thats a great example, thanks Jeff.
    but when I run the same example and run the Test, the code coverage is 0% , can you please explain me in brief how to write a test class for such a WebService Callout please.

  8. Integrate reCAPTCHA with Force.com at Cloud Giga

    [...] only a rather simple ‘GET’ example. Jeff Douglas had in his blog thrown out some good example of snippets on this topic. Here’s what I [...]

  9. Girish Suravajhula

    Awsome post. Helped me a lot. Thanks

  10. rajesh

    this is my code

    public class lll {

    public string errormessage;

    public void Login()
    {
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    //ErrorMessage=”;
    final string baseUrl = ‘http://dskvapconsultancyservices.createsend.com/’;
    final string username = ’05b88f78dfc4f00ce93553a79be93d04′;
    final string password = ‘rajesh12′;

    string apikey=’05b88f78dfc4f00ce93553a79be93d04′;
    Blob headerValue = Blob.valueOf(username + ‘:’ + password);
    String authorizationHeader = ‘BASIC ‘ +
    //EncodingUtil.urlEncode(headerValue);
    EncodingUtil.base64Encode(headerValue);
    req.setHeader(‘Host’,'http://api.createsend.com’);
    req.setHeader(‘Content-length’, ’1753′ );

    req.setHeader(‘Connection’,'keep-alive’);
    req.setHeader(‘Content-Type’, ‘application/xml;charset=UTF-8′);
    req.setHeader(‘Authorization’,authorizationHeader);
    //req.setHeader(‘Authorization’,'Basic 05b88f78dfc4f00ce93553a79be93d04==’);
    //req.setHeader(‘content-type’, ‘text/xml;charset=utf-8′);
    //req.setHeader(‘Content-Length’,’1024′);
    //req.setHeader(‘Host’,'http://dskvapconsultancyservices.createsend.com/’);
    //req.setHeader(‘Connection’,'keep-alive’);
    string body1=”;
    body1+=”;
    body1+=’ ‘;
    body1+=’05b88f78dfc4f00ce93553a79be93d04′;
    body1+=”;
    body1+=’05b88f78dfc4f00ce93553a79be93d04′;
    body1+=’23′;
    body1+=”;
    body1+=”;
    body1+=”;
    body1+=”;
    body1+=”;
    body1+=”;

    req.setMethod(‘GET’);
    req.setBody(body1);

    //req.setEndpoint(baseUrl + ‘?loginType=&un=’+username+’&pw=’+password);
    //req.setEndpoint(‘http://api.createsend.com/05b88f78dfc4f00ce93553a79be93d04/v3/clients/clients.xml’);
    req.setEndPoint(‘http://api.createsend.com/api/v3/clients.xml’);
    //req.setbody(‘http://api.createsend.com/api/v3/clients.xml’);

    HttpResponse res = h.send(req);
    //req.setEndpoint(baseUrl + ‘apex/UploadFile_DifferentOrg’);

    // res = h.send(req);
    system.debug(‘********’+res.getbody());
    if (res.getBody().indexOf(‘success=true’)>-1)
    {
    system.debug(‘Success’);
    }
    }

    public void detail()
    {

    }

    }

    i am getting errors like
    400Failed to deserialize your request.
    Please check the documentation and try again.
    Fields in error: client
    ..
    System.HttpResponse[Status=Bad Request, StatusCode=400]

    please help me in this area

    thank you in advance

  11. rajesh

    i want to integrate salesforce with campaign monitor
    please help me

  12. chayakiran

    Hi,
    Can we consume RPC based WSDL using HTTP Callouts?
    Could you please provide some references?
    Thanks,
    Chayakiran

  13. Jeff Douglas

    I believe there are some recipes on http://developer.force.com/cookbook.

Leave a comment

Feed

http://blog.jeffdouglas.com / RESTful Web Service Callout using POST with Salesforce.com

WordPress Appliance - Powered by TurnKey Linux