Creating an AJAX Web App Using the Bit.ly API

Over the past few years, the web has seen an explosion in the number of URL shorteners. A lot of this growth is due to popular microblogging and social networking sites such as Twitter. With this growth, comes the demand for custom use and the ability for developers to create their own apps to take advantage of the shortening service. Today, we will use Twitter’s url shortener of choice and create an AJAX web app using the bit.ly API and the jQuery library.

Final Demo

You can check out what we will finally achieve after this tut at the online demo page.

What exactly is an API?

A web API stands for Application Programming Interface. So what exactly does this mean? Basically, an API allows developers and programs to access certain areas of a web or software application in order to produce a desired result. This could mean making a request to Twitter using a custom script you have created to pull put out your latest tweets. It could also mean calling the bit.ly API with a php script to create your own short URLs.

Bitly Home Screenshot

Generally, most APIs require a username and a unique API key mapped to that username. This is helpful for a few reasons. One, this allows the API to cut back on spam by ensuring users have registered and “proved” themselves to be human. Secondly, it allows developers access to other members profiles and data (if the API allows it), and because we are using their API key and not a password, they can keep their credentials to themselves. For example, some of the web applications that use the Envato API require your API key in order to display your most recent sales. You can safely give this to a web app (assuming you trust it enough to access your sales) because you are still keeping your password secret. In addition, you can change your API key at any time to void your current one.

For more information on APIs in general, please see the wiki link posted above.

Introducing the Bit.ly API

API Screenshot

The bit.ly API is hosted on google code and is available to the general public. As of writing, the current version is at version 2.0.1. When new versions are released, it is best to update to the latest version, keep that in mind.

Authentication

If you take a look at the bit.ly API wiki, you will notice the first paragraph after the introduction talks about authorization to the API. As discussed earlier, most APIs require some sort of authorization before you are granted access. The bit.ly API is no different. To get access, you will need to follow the below steps.

  1. Head over to the bit.ly home page and register a new account if you do not have one already. Make a note of your username as you will need it shortly.
  2. After you have logged in, click on the account link located at the upper right hand corner of the page.
  3. Scroll down and note your API key, we will be using this to access the Bit.ly API shortly. Remember that you can reset your ket at anytime by accessing this page and clicking reset.

Now that we have our login and API key noted, we can move on to making our first simple request.

Shortening a URL

Before we take a look at the markup and steps we need to take, it is important to keep in mind users without Javascript enabled. Since we are going to be using AJAX calls, we need to plan ahead for what will happen if the user does not have Javascript enabled. We will create this application with that in mind, and make sure that it will still function without Javascript!

We have all we need to start creating our AJAX based URL shortening application. First, we will start with some basic markup:

 
		<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
	<meta name="author" content="Drew Douglass" />
	<title>AJAX URL Shortener With the Bit.ly API</title>
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style type="text/css" media="screen">
body {
	background-color:#d9d9d9;
	color:#212121;
	font-family:Gill sans, arial, sans-serif;
 
}
h1, h3, h3, h4, h5, h6 {
	font-family:Helvetica, arial, Verdana, sans-serif;
	text-shadow: 0px 1px 1px #999;//For those of you with decent browsers ;-)
}
h1 {
	font-size:29px;
	margin:30px auto;
	width:960px;
}
small {
	font-size:13px;
 
}
#wrap {
	width:960px;
	margin:0 auto;
	background-color:#fafafa;
	border:1px dashed #999;
	padding:20px;
 
}
.box {
	border:1px dashed #999;
	text-align:center;
	margin:20px 60px;
}
.response_bg {
	background-color:#ccc;
	width:600px;
	margin:10px auto;
	padding:10px 0px;
}
</style>
</head>
 
<body>
	<h1>Shrink/lengthen/find out more info about a URL.<small> All thanks to the <a href='http://code.google.com/p/bitly-api/wiki/ApiDocumentation'>bit.ly API</a></small></h1>
	<div id='wrap'>
 
		<!--Bitly shorten-->
		<div class='box'>
			<h3>Shorten a URL</h3>
			<form action='shorten.php' method='post'>
				<p>URL to shorten:</p>
				<p><input id='long_val' type='text' name='long_url' value='' />
				<input id='submit_short' type='submit' name='shorten_submit' value='Shorten!' /></p>
 
				<div class='loader'></div>
				<p class='response'></p>
			</form>
		</div>
 
	</div>		
</body>
</html>

You will notice a few things about the markup above. First, we are importing the latest version of jQuery from the google AJAX library. This will allow us to take advantage of super simple AJAX calls with jQuery. Second, the inline styling is just for the demo, of course feel free to use your own. Third, notice the form is posting to another page and not itself, this page will hold our php logic and make the actual API call. The user inputs a ‘long url’, the page is submitted to shorten.php, the back end work is executed and the data returned. In addition, notice that we have two empty div classes, one named loader and one named response. These divs will respectively hold the AJAX loading gif and the data returned from the request. That said, create a new file and name it shorten.php. Our shorten.php file will look like so:

<?php
if(isset($_POST['long_url']) && !empty($_POST['long_url'])){
	$input_url = strip_tags(trim($_POST['long_url']));
 
	//Ensure that the url is valid, php 5+ required 
	if(!filter_var($input_url, FILTER_VALIDATE_URL)){
		echo 'Invalid URL.';
	}
	else{
		$url_enc = urlencode($input_url);
		$version = '2.0.1';
		$login = 'drewdouglass';
		$api_key = 'R_d57e0485e4d091e874bec0bdd7716801';
		$format = 'json';
		$data = file_get_contents('http://api.bit.ly/shorten?version='.$version.'&login='.$login.'&apiKey='.$api_key.'&longUrl='.$url_enc.'&format='.$format);
		$json = json_decode($data, true);
 
		foreach($json['results'] as $val){
			echo $val['shortUrl'];
		}
	}
}
else {
	echo 'Null or empty URL given.';
}
?>

Please note I have changed my API key, no use trying to use it ;)

I will walk through the above code step by step below:

  1. We first check to ensure the form has been submitted, if not we output Null or empty url given. Feel free to be more descriptive than this.
  2. If the form was indeed submitted, we strip all tags out of the inputted data for security reasons. There shouldn’t be any tags in a URL anyway, so this won’t be a problem.
  3. Now, we check to make sure the URL is valid. We use the php 5 filter_var function which makes validating user input (such as emails and URLs) a breeze. If you are running php 5, do yourself a favor and get familiar with filter_var.
  4. Assuming the input URL is a valid one, we will go on and set up all of our needed variables to make the request. From top to bottom: the encoded version of our URL, the version of the API to use, our login/username, the API key you got when you signed up, the format we want the data returned in (JSON by default, XML can also be used).
  5. Once we have all of the variable mentioned above, we can store our http request in the data variable. We make a call to file_get_contents to make the request. Most servers have this enabled by default and it makes http requests a breeze. If you do not have it enabled, you can ask your web host or look into a solution using cURL.
  6. Now that we have our request results stored in a variable, we can use json_decode to convert the data from JSON to an associative array.
  7. Lastly, we loop through the results given and output the shortened URL.

This is all well and good, and it certainly gets the job done, but if you run this script now, you will notice a page refresh takes you to a new page (shorten.php) where the data is displayed in a somewhat ugly fashion. Wouldn’t it be great if we did not need a page refresh ans just used an AJAX call to that file instead? Then let’s do it!

We will program the Javascript procedurally to make this very easy to follow. In the head section of your HTMl, after importing the jQuery library, add some Javascript tags with the following code.

$(function(){
var ajax_loader = '<img src="ajax-loader.gif" alt="" />';
$('.response').hide();
$('.loader').hide();
$('#submit_short').click(function(){
 
		//Show AJAX loader 
		$('.loader:eq(0)').html(ajax_loader).show(500, function(){
 
			//Perform request
			$.post('shorten.php', {long_url: $('#long_val').val()}, function(data){
 
				//Hide the AJAX loader 
				$('.loader:eq(0)').hide(500, function(){
 
					//Show the response
					$('.response:eq(0)').addClass('response_bg').html(data).fadeIn(1000);
				});
			});
		});
 
 
	return false;
});
 
});

I have done my best to comment the jQuery script above, but I will walk through it slowly again below:

  1. We store the HTML for our spinning AJAX loader in a variable named ajax_loader. We will use this to show the user their request is pending.
  2. Next, we hide both the response and loader classes in case they are visible from a previous request for any reason.
  3. When the user click the submit button to shorten a URL, we attach a function to this event. This function begins by showing the spinning AJAX loader in the first loader class (as we will have multiple loader classes we are accessing it using the eq() method).
  4. After we have shown the loader, we will perform the AJAX request using post. We pass the POST key and value to the AJAX request and attach a callback function to be executed when the request is complete. Also, notice how we have passed a data variable to the callback. This will allow us access to the return string.
  5. Once the request is finished, the callback function hides the AJAX spinner.
  6. Lastly, the jQuery script adds a custom class to the response class and fades in the returned data, in this case the shortened URL, over a period of half of a second.
  7. One more thing, we need to return false at the end to override the original form controls. If we did not, the page would refresh to shorten.php upon submitting the form.

Go ahead and try it out on your server with your API key and login, use a generic url such as google or something of that nature. Not too shabby huh? Assuming all went well, you should get something like the screenshot below:

Shorten Screenshot

Expanding or lengthening a URL

A really cool feature of the API is that shortening is not the only thing we can do. In addition, we can actually pass the API a bit.ly URL and find out the original, long url. I will go over all of the steps to do this, in a little less detail this time, as hopefully you all understand the basic markup and request by now. Create a new form on your HTML page, you should now have two forms like so:

<!--Bitly shorten-->
<div class='box'>
	<h3>Shorten a URL</h3>
	<form action='shorten.php' method='post'>
		<p>URL to shorten:</p>
		<p><input id='long_val' type='text' name='long_url' value='' />
		<input id='submit_short' type='submit' name='shorten_submit' value='Shorten!' /></p>
 
		<div class='loader'></div>
		<p class='response'></p>
	</form>
</div>
 
<!--Bitly expand-->
<div class='box'>
	<h3>Lengthen a bit.ly URL</h3>
	<form action='lengthen.php' method='post'>
		<p>URL to lengthen:</p>
		<p><input id='leng_val' type='text' name='lengthen_url' value='' />
		<input id='submit_long' type='submit' name='lengthen_submit' value='Lengthen!' /></p>
 
		<div class='loader'></div>
		<p class='response'></p>
	</form>
</div>

Nothing really new here. We are posting to a different php page as you have probably noticed, that will handle all of the logic for expanding a bit.ly URL. The only new markup here is some different unique IDs that we can take advantage of when writing our jQuery AJAX request. Now that we have another form, create a new file called lengthen.php and fill it with the following php:

<?php
if(isset($_POST['lengthen_url']) && !empty($_POST['lengthen_url'])){
	$input_url = strip_tags(trim($_POST['lengthen_url']));
 
	//Ensure that the url is valid, php 5+ required 
	if(!filter_var($input_url, FILTER_VALIDATE_URL)){
		echo 'Invalid URL.';
	}
	else {
		$url_enc = urlencode($input_url);
		$version = '2.0.1';
		$login = 'drewdouglass';
		$api_key = 'R_d57e0485e4d091e874bec0bdd7716801';
		$format = 'json';
		$data = file_get_contents('http://api.bit.ly/expand?version='.$version.'&shortUrl='.$url_enc.'&login='.$login.'&apiKey='.$api_key.'&format='.$format);
		$json = json_decode($data, true);
 
		foreach($json['results'] as $val){
			echo $val['longUrl'];
		}
 
	}
}
else {
	echo 'Invalid or null url.';
}
?>

We are doing nearly the exact same thing as when we were shortening our URLs, only this time the request goes to the expand API instead of the shorten. Please note that we are using all of these different php files to demonstrate the different uses of the API, of course, we could have this all in one php file and display different data depending on certain GET requests, but this will more than do for the purpose of this article. Just know that if you like to have all of your logic in one file for this sort of thing, you are more than free to do so.

Now we need to write some Javascript again, this time we need to make the request to our lengthen.php page. The overall logic though is exactly the same:

	$('#submit_long').click(function(){
		//Show AJAX Loader
		$('.loader:eq(1)').html(ajax_loader).show(500, function(){
			//Perform request 
			$.post('lengthen.php', {lengthen_url: $('#leng_val').val()}, function(data){
				//Hide Ajax loader
				$('.loader:eq(1)').hide(500, function(){
					//Show response 
					$('.response:eq(1)').addClass('response_bg').html(data).fadeIn(1000);
				});
			});
		});
	return false;
});

Seem familiar? Well it is! In fact, we could probably move all of our jQuery scripts to a plugin or custom function to cut back on some typing, but that is not the point of this tut. Assuming all went well, you should now have a result that looks something like the screenshot below:

Expand Screenshot

Ok, so shortening and expanding bit.ly URLs is a lot of fun and pretty cool, but what about more? We want more information about these URLs! What if we wanted to know how many total clicks or user clicks a certain bit.ly URL has had? How do we get these stats? We can ascertain this info using the stats API call. The form code for this will not look any different than our other HTML forms. Below will do just fine:

<div class='box'>
	<h3>Get stats about a bit.ly url</h3>
	<form action='stats.php' method='post'>
		<p>Bit.ly URL:</p>
		<p><input id='stat_val' type='text' name='stat_url' value='' />
		<input id='submit_stat' type='submit' name='submit_stat' value='Get Stats!' /></p>
 
		<div class='loader'></div>
		<p class='response'></p>
	</form>
</div>

Nothing you have not seen here, we are now posting to a page named stats.php. Furthermore, we have attached unique IDs that we can use shortly with our AJAX call. Create a new file named stats.php and paste the following code:

<?php
if(isset($_POST['stat_val']) && !empty($_POST['stat_val'])){
	$input_url = strip_tags(trim($_POST['stat_val']));
 
	if(!filter_var($input_url, FILTER_VALIDATE_URL)){
		echo 'Invalid URL.';
	}
	else {
		$url_enc = urlencode($input_url);
		$version = '2.0.1';
		$login = 'drewdouglass';
		$api_key = 'R_d57e0485e4d091e874bec0bdd7716801';
		$format = 'json';
 
		$data = file_get_contents('http://api.bit.ly/stats?version='.$version.'&shortUrl='.$url_enc.'&login='.$login.'&apiKey='.$api_key.'&format='.$format);
		$json = json_decode($data, true);
 
		//print_r($json);
		foreach($json['results'] as $key => $val){
			if(is_array($val)){
				continue;
			}
			echo $key . ' = ' .$val . '<br />';
		}
	}
}
else {
	echo 'Null or invalid URL.';
}
?>

Notice how the print_r call is commented out below? If you ever need to debug or get a good view of all the returned data (especially helpful with objects and arrays) then it is a great idea to use print_r or var_dump, although keep in mind these should only be used for debugging, not on a site with visitors.

We have made our http request to the stats API this time around. You might also notice that our loop looks a little bit different this time. If you run print_r on the returned data, you will see there is a ton of data that we really just don’t need to display inside a nested array. Therefore, when looping through the desired array, if we stumble upon another array, we simply use a continue statement to skip it and continue looping through our data.

Let’s quickly take a look at the Javascript for this request, it’s nothing you haven’t seen already:

	$('#submit_stat').click(function(){
	//Show ajax loader 
	$('.loader:eq(2)').html(ajax_loader).show(500, function(){
		//Perform request 
		$.post('stats.php', {stat_val: $('#stat_val').val()}, function(data){
			//Hide ajax loader when request is given back 
			$('.loader:eq(2)').hide(500, function(){
				//Show response once loader is hidden 
				$('.response:eq(2)').addClass('response_bg').html(data).fadeIn(1000);
			});
		});
	});
	return false;
});

A sample screenshot of some return data is shown below:

Stats Screenshot

Let there be thumbnails!

So far, we have covered some pretty cool uses of the bit.ly API. An even cooler feature, however, is the ability to pull thumbnails of an existing bit.ly URL. This can be useful to get an idea of what a certain website looks like without visiting it. In addition, the API allows you to get a small, medium, or large thumbnail back. It’s up to you. As always, HTML form time:

<!--Bitly Thumbnail-->
<div class='box'>
	<h3>Grab the thumbnail of a bit.ly URL</h3>
	<form action='thumbnail.php' method='post'>
		<p><input id='thumbnail_val' type='text' name='thumbnail_val' value='' />
		<input id='thumb_submit' type='submit' name='thumb_submit' value='Get Thumbnail!' /></p>
 
		<div class='loader'></div>
		<p class='response'></p>
	</form>
</div>

Next we need our php script named thumbnail.php, go ahead and create it and paste in the following code:

<?php
if(isset($_POST['thumbnail_val']) && !empty($_POST['thumbnail_val'])){
	$input_url = strip_tags(trim($_POST['thumbnail_val']));
	if(!filter_var($input_url, FILTER_VALIDATE_URL)){
		echo 'Invalid URL.';
	}
	else {
		$url_hash = '';
		$url_enc = urlencode($input_url);
		$version = '2.0.1';
		$login = 'drewdouglass';
		$api_key = 'R_d57e0485e4d091e874bec0bdd7716801';
		$format = 'json';
 
		//Notice the keys parameters, we can specify we only want a certain amount of info returned.
		$data = file_get_contents('http://api.bit.ly/info?version='.$version.'&shortUrl='.$url_enc.'&login='.$login.'&apiKey='.$api_key.'&format='.$format.'&keys=thumbnail');
		$json = json_decode($data, true);
 
		//print_r($json);
		foreach($json['results'] as $key => $val){
			$url_hash = $key;
		}
		if(empty($json['results'][$url_hash]['thumbnail']['medium'])){
			echo 'Could not grab thumbnail.';
		}
		else {
			echo '<img src="'.$json['results'][$url_hash]['thumbnail']['medium'].'" />';
		}
	}
}
else {
	echo 'Invalid or null URL.';
}
?>

Take a careful look at the data variable in this specific script. Did you notice how we added an extra parameter named ‘keys’ onto the end of the string? This is because the info version of the API allows use to specify certain information we want back. That way we don’t get a giant amount of return data, only the thumbnails we are after. Lastly, it’s just a matter of looping through the return format and outputting the thumbnail.

I have chosen to output medium thumbnails, but you can replace this value with small or large if you like. One last thing is the jQuery needed, and you should have this down by now:

	$('#thumb_submit').click(function(){
	//Show ajax loader 
	$('.loader:eq(3)').html(ajax_loader).show(500, function(){
		//Perform ajax request 
		$.post('thumbnail.php', {thumbnail_val: $('#thumbnail_val').val()}, function(data){
			//Hide ajax loader when response is returned 
			$('.loader:eq(3)').hide(500, function(){
				//Show response after hiding loader
				$('.response:eq(3)').addClass('response_bg').html(data).fadeIn(1000);
			});
		});
	});
	return false;
});

Please note this may now work on URl that were just created using the bit.ly API, as the web service needs some time to create all of the thumbnails. An example output of this is seen below:

Bitly Thumbnail Screenshot

Live Demo

You can view the final live demo at anytime to check out the results of this tutorial.

Extra Credit

Hopefully, you have learned the basics of working with the bit.ly API and learned a bit about php and jQuery as well. If you are looking for more of a challenge, here are a few ideas:

  • Create a jQuery plugin or function to reduce all of the jQuery we need to write. Bonus points if you redistribute it for others to use.
  • Condense all of the PHP files into one file and separate what data to return based on GET requests or other methods. In addition, you could create a php function or class to cut back on some code.
  • Create your own APP using the bit.ly API and show me your creativity!

Do you have a URL shortener API of choice you use frequently? Did you learn something today? Let us know what you think in the comments section below!



13

Comments