This post is inspired by Jared Baker who asked about how to integrate Salesforce and Bitly to create short urls to include in email alerts.

This was a fun challenge and I ended up using @InvocableMethod apex class so that the URL shortening could be kicked off by Process Builder. In my example below, I added a custom field “Short URL” to the Case object. I have a single Process that kicks off when a Case is created or updated and monitors when the “Short URL” field changes. If the field is blank then it calls out to Bitly to generate the url asynchronously (the async part is important and I’ll discuss that later). When the “Short URL” field becomes non-blank then Process Builder sends an email alert to the case owner with the shortened link.

Step 1. Sign-up for Bitly (FREE)

To use the Bitly API you will need to register. You can sign-up using Twitter, Facebook, or create a new login with their service. I chose to create a Bitly specific login because I don’t like sharing my social logins with websites.

Step 2. Create Named Credential in Salesforce

In Salesforce, go to Setup | Security Controls | Named Credentials and create a new Named Credential to store your Bitly username/password. Even though Bitly discourages us from storing the password, I think it’s ok in this scenario because (a) it’s ours and not someone else’s, and (b) Named Credentials stores the password securely and once set it’s no longer visible to other users. To me, that has a lot more security to it than if we were to store the Access Token in a Custom Setting.

bitly_named_credential

Step 3. Create Custom Field “Short URL”

Create a custom URL field on your objects of interest to store the Bitly generated short urls. Depending on your situation you may have one or more. The sample code I share only supports one on the Case object, but you can easily adapt the code to your needs.

Step 4. Create Bitly Apex Classes

I developed two classes, one that encapsulates the Bitly http callouts and the other to expose the service as @InvocableMethod so it can be invoked by Process Builder. An important point to note is that the BitlyShortenURLInvocable class actually calls a @Future method to generate the short urls asynchronously. This is required because if you don’t then you’ll get an error in Process Builder that you have uncommitted work and you must either commit or rollback before making the http callout to the Bitly service. When the async process completes then it updates the Case objects with the new short urls which Process Builder will pick up on the change then send the email alert (or whatever you want it to do).

/**
* Simple service to make http callout to
* Bitly url shortener service.
*/
public class BitlyService {
// reusable access token for oauth,
// required when making API requests
private String accessToken;
public BitlyService() {
this.accessToken = getAccessToken();
}
/**
* Given a long URL will return the shortened version.
* http://dev.bitly.com/links.html#v3_shorten
*/
public String shorten( String url ) {
HttpRequest req = new HttpRequest();
req.setEndpoint(
'callout:Bitly/v3/shorten' +
'?access_token=' + this.accessToken +
'&longUrl=' + EncodingUtil.urlEncode( url, 'UTF-8' ) +
'&format=txt'
);
req.setMethod('GET');
Http http = new Http();
HttpResponse res = http.send(req);
return res.getBody();
}
/**
* Get the access token to make authenticated oauth calls.
* The actual username/password credentials are stored in
* Named Credentials so that the password is stored securely.
*
* This does require an extra http request when instantiating
* the service which adds to latency. Alternatively, you could
* store the generated access token in a custom setting and simply
* reference it from your code, but then anyone who can view
* custom settings can view the access token and use the API.
* Trade-offs.
*/
private String getAccessToken() {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Bitly/oauth/access_token');
req.setMethod('POST');
Http http = new Http();
HttpResponse res = http.send(req);
return res.getBody();
}
}

view raw
BitlyService.java
hosted with ❤ by GitHub

public class BitlyShortenURLInvocable {
@InvocableMethod(
label = 'shorten'
description = 'Given case IDs then generates a bitly short url for them'
)
public static List<String> shorten( List<ID> caseIds ) {
// You can't invoke http callouts from Process Builder or Flow
// because the database transaction has not committed yet, you will get error:
// "System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out"
// To get around this then we'll actually make the call in a @Future method asynchronously.
shortenAsync( caseIds );
return new List<String>();
}
@Future( callout = true )
private static void shortenAsync( List<ID> caseIds ) {
// Fetch your data and a field where you want to store the generated short url
List<Case> cases = new List<Case>([ SELECT id, short_url__c FROM case WHERE id IN :caseIds ]);
// Service to actually call out to bitly and get a shortened url
BitlyService service = new BitlyService();
// Bitly does not support bulk url shortening
// so you must make each call individually.
// Do be aware of Bitly's rate limiting if you try
// to mass create a bunch of records in short succession
// http://dev.bitly.com/rate_limiting.html
for ( Case caseObj : cases ) {
// in this trivial example, we're just creating short urls to the record itself
caseObj.short_url__c = service.shorten( 'https://login.salesforce.com/' + caseObj.id );
}
// update the records with their short urls
// use workflow or trigger to fire off the short url field being populated
// to then send email alerts, etc. including the short url
if ( cases.size() > 0 ) {
update cases;
}
}
}

I do not have any test classes for this code yet. As of 2/12/2016, I have written some simple test classes available on this gist. For more information, check out this article: Testing HTTP Callouts.

Step 5. Create Process to Automate URL Shortening

In our simple example, navigate to Process Builder to create a new Process on the Case object whenever it is created or edited.

  1. The first decision criteria should check if the custom “Short URL” field is blank.
    1. If true then call apex class BitlyShortenURLInvocable passing in the case record’s ID
  2. The second decision criteria should check if the custom “Short URL” field is not blank and was changed.
    1. If true then send an email alert or some other action to use the now populated “Short URL” field

bitly_process_builder

Step 6. Create a New Case!

Activate your Process then go to create a new Case. Once saved, you may need to refresh the page after a couple seconds and then you’ll notice the “Short URL” field has been populated. Voila!

bitly_case

In this example, I setup a simple email alert to the Case owner with the short url link as shown in this screen shot:

bitly_email_alert