Skip to Main Content
Official App
Free – Google Play
Get it
FreshBooks is Loved by American Small Business Owners
FreshBooks is Loved by Canadian Small Business Owners
FreshBooks is Loved by Small Business Owners in the UK
Dev Blog

Putting External Services Behind AJAX

by coe on June 15/2010

I’ve recently been tasked with various usability fixes at FreshBooks. Many of my tweaks leverage useful third-party web-services like geo-location lookup, adding a bit of punch to the user-experience. Being the prudent/paranoid software developer that I am, the idea of an external dependency dying and bringing down a mission-critical page terrifies me — not to mention my manager has a giant (granted Nerf) sword.

In conjunction with these usability changes, fellow FreshBooks developer Mark Story and I tore apart FreshBooks’ AJAX controller, making it much easier to talk to FreshBooks via JavaScript. Working on these two tasks at the same time turned on a lightbulb for me. Historically, I had been putting potentially risky web-service calls behind curl, with a timeout and exception handling. This was suboptimal since if a third-party web-service was not responding, the non-mission-critical bell and/or whistle that depended on it could greatly impede the user experience of a page. I needed a better solution.

Here it is:

  • A wrapper class for the external web-service
  • A controller for interacting with the external dependency
  • A JavaScript library that interacts with the controller
  • Third-party non-mission-critical services are only accessed asynchronously through JavaScript

Here’s why this approach is awesome:

  • If the external web-service goes down, only the .ajax() call fails — if designed properly, the calling page continues to function.
  • You end up with a bunch of nicely abstracted, reusable JavaScript plugins for adding sugar to your user-interface. For instance, here’s a plugin I built using this approach:
  • Given a link element replaces it with the short-form,
  • or can be passed a URL directly and encodes it. *
  • @param params.callback callback to return encoded URL to.
  • @param params.longUrl long URL, if not explicitly interacting with a jQuery element.
  • @return void either the callback is executed, or the href attribute of the jQuery element is set. */ jQuery.fn.bitly = function(params) { var params = params || {}; var $this = $(this); var fromUrl = false; var longUrl = params.longUrl || ''; if ($this.attr('href')) { longUrl = $this.attr('href'); // Grab the URL from a jQuery element. fromUrl = true; } $.ajax({ url: '/ajax/externalAPI/bitlyEncode', data: , dataType: 'json', success: function (data) { if (fromUrl && data.url) { // If we provided an element, we assume it's a link and set the href. $this.attr('href', data.url); } if (params && params.callback) { // execute callback with encoded URL. params.callback(data['url']); } } }); };

This little snippet of code takes a selector, e.g., $(‘a’), connects to our ‘externalAPI’ controller, invokes the ‘bitlyEncode’ action, and replaces a link’s href with the shortened URL. What if the AJAX call fails? The URL just maintains its original long form. You can see this in action, from your FreshBooks account on the ‘Refer FreshBooks’ page.

So there you have it: a straight-forward approach to safely adding third-party bells/whistles to a page — without having to worry about your manager’s sword.