cURL is simply a command-line utility, written in C, that runs on a variety of binary platforms (Windows, Linux, Solaris, etc). Arguably, almost anything you can do with cURL you can do with Apex Code. Heroku can't readily determine a request from cURL versus Apex Code versus a telnet connection with the appropriate code copy-pasted from Notepad.
What you need to know is the method (POST), the headers required (Content-Type, Content-Length, etc), and the expected payload (XML, JSON, URL-encoded, etc). Once you know the expected format, you can then proceed to perform your POST. The tricky part is that Apex Code is a bit more "low level" than cURL, in the sense that you, as the developer, have more input into how the message is formed.
The single exception to this rule is that Apex Code doesn't handle binary data very well. It usually has to be encoded in base64 before you send it out. This will modify the types of headers you may need to use. However, unless the third party resource only accepts binary data streams (rare), there's a very likely possibility that you can indeed call this resource using Apex Code, since Apex Code uses the same HTTP standards that everything else uses (web browsers, cURL, and so on).
You should probably ask the host if they can provide valid payloads for you to examine, so you can figure out how to replicate them in Apex Code. Assuming they have some decent documentation, you should probably be able to figure out everything you need to know using just their documentation plus the salesforce.com documentation.
Given this comment:
curl -i -X POST --data "first_name=test&last_name=testlast&email=test@test.com&phone=1234567&company=AcmeInc&years_in_business=3&amount=4000&dealer_id=524b2833f7494317db000001" https://example.com/webform/start/
The code you need would be approximately:
String payload = 'first_name=test&last_name=testlast&email=test@test.com&phone=1234567&company=AcmeInc&years_in_business=3&amount=4000&dealer_id=524b2833f7494317db000001';
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://example.com/webform/start/');
req.setHeader('Content-Type','application/x-www-form-urlencoded');
req.setHeader('Content-Length',String.valueOf(payload.length()));
req.setBody(payload);
Http binding = new Http();
HttpResponse res = binding.send(req);
Most likely, the pieces you missed was the Content-Type (needs to be form encoded), and possibly the Content-Length (needs to be the total size of the body). You may need to tweak this a bit to work, but this should be close.
The ffhttp library should do the trick: https://github.com/financialforcedev/ffhttp-core
It includes error handling, redirections, building header fields, oauth, mime attachments and more.
EDIT - Sample code
Say you want to consume the JSONPlaceholder /users rest resource.
You could create a Named Credential for the URL.
Then you can use ffhttp to make the request, handle the failure or successful response and deserialize into the intended format. FFHTTP only includes an OAuth client but it's pretty simple to create your own...
public with sharing class ffhttpSample {
/*
* DTO for remote object result
*/
private class RemoteUser {
Integer id;
String name;
String username;
String email;
}
/*
* Vanilla HTTP request
*/
public static RemoteUser[] getUsers() {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:JSONPlaceholder/users');
request.setMethod('GET');
HttpResponse response = http.send(request);
if (response.getStatusCode() == 200) {
return (RemoteUser[])JSON.deserialize(response.getBody(), List<RemoteUser>.class);
} else {
System.debug(response.getStatus());
return new RemoteUser[]{};
}
}
/*
* FFHTTP request
*/
public static RemoteUser[] getUsersFfhttp() {
SimpleClient client = new SimpleClient();
client.setCredentials(new ffhttp_Client.NamedCredentials('JSONPlaceholder'));
SimpleClientRequest request = new SimpleClientRequest(
client,
'/users',
ffhttp_Client.REQUEST_METHOD_GET,
new ffhttp_JsonDeserializer(List<RemoteUser>.class));
// Execute and parse the response.
// Alternatively you can use executeUnparsed() to return the response body as a String
return (RemoteUser[])request.execute();
}
/*
* FFHTTP client implementations
*/
private class SimpleClient extends ffhttp_Client.AbstractClient {}
private class SimpleClientRequest extends ffhttp_Client.AbstractClientRequest {
SimpleClientRequest(IAbstractClient client, String endpoint, String requestMethod, ffhttp_IDeserialize deserializer) {
super(client, endpoint, requestMethod, null, deserializer);
}
}
}
Best Answer
About the closest thing to Apex libraries is the 'Force.com Labs' apps on the AppExchange that are open-source packages.
They're a good source for some specific code. However, they're not typically distributed as library code.
Also, Force.com's Github contains a good set of SDKs and code-source files for linking into SFDC from a variety of languages and platforms.