Bit.ly Class for shortening URLs in VB.NET and C#

So I was tinkering around with some code and thought “Hey, wouldn’t it be great to create a class that could be used to tie into bit.ly’s API for shortening URLs?” After having this thought I also thought “I am hungry” so went to get some lunch. Then when I came back, I got to work putting together a quick class that a programmer could use in their projects for submitting long URLs for bit.ly to shorten up. I created it in two .NET languages so that it would be more versatile and save some programmers from having to port it from one language to the other. Now lets get shortening on this episode of the Programming Underground!

The idea behind our class is that we are going to first create the object with a default login and API key or provide our own. By calling the method “Shorten” and giving it a nice long URL we are going to…

1) Contact bit.ly using their API URL
2) Fetch the result from bit.ly in XML format
3) Parse that XML to fetch the “shotUrl” element
4) Return that element’s value to the caller of the method

The whole process is pretty straight forward. Being that we are counting on an external source that may or may not respond, could provide a bad response, or just plain ignore us we have to build in a few error handling traps. We want to make sure this class works even if the underlying API isn’t. Let’s start with the VB.NET version of this class and then we will move on to the C# version. These classes can be placed in their own class file and called from anywhere in the project.

Imports System.Text
Imports System.Xml
Imports System.IO
Imports System.Net

Public Class bitly
	Private loginAccount As String
	Private apiKeyForAccount As String

	Private submitPath As String = "http://api.bit.ly/shorten?version=2.0.1&format=xml"
	Private errorStatus As Integer = 0
	Private errorStatusMessage As String = ""


	' Constructors (overloaded and chained)
	Public Sub New()
		Me.New("bitlyapidemo", "R_0da49e0a9118ff35f52f629d2d71bf07")
	End Sub


	Public Sub New(ByVal login As String, ByVal APIKey As String)
		loginAccount = login
		apiKeyForAccount = APIKey

		submitPath &= "&login=" & loginAccount & "&apiKey=" & apiKeyForAccount
	End Sub


	' Properties to retrieve error information.
	Public ReadOnly Property ErrorCode() As Integer
		Get
			Return errorStatus
		End Get
	End Property

	Public ReadOnly Property ErrorMessage() As String
		Get
			Return errorStatusMessage
		End Get
	End Property


	' Main shorten function which takes in the long URL and returns the bit.ly shortened URL
	Public Function shorten(ByVal url As String) As String

		errorStatus = 0
		errorStatusMessage = ""

		Dim doc As XmlDocument
		doc = buildDocument(url)

		If Not doc.DocumentElement Is Nothing Then

			Dim shortenedNode As XmlNode = doc.DocumentElement.SelectSingleNode("results/nodeKeyVal/shortUrl")

			If Not shortenedNode Is Nothing Then

				Return shortenedNode.InnerText

			Else

				getErrorCode(doc)

			End If
		Else

			errorStatus = -1
			errorStatusMessage = "Unable to connect to bit.ly for shortening of URL"
		End If

		Return ""

	End Function


	' Sets error code and message in the situation we receive a response, but there was
	' something wrong with our submission.
	Private Sub getErrorCode(ByVal doc As XmlDocument)

		Dim errorNode As XmlNode = doc.DocumentElement.SelectSingleNode("errorCode")
		Dim errorMessageNode As XmlNode = doc.DocumentElement.SelectSingleNode("errorMessage")

		If Not errorNode Is Nothing Then

			errorStatus = Convert.ToInt32(errorNode.InnerText)
			errorStatusMessage = errorMessageNode.InnerText
		End If
	End Sub


	' Builds an XmlDocument using the XML returned by bit.ly in response 
	' to our URL being submitted
	Private Function buildDocument(ByVal url As String) As XmlDocument

		Dim doc As New XmlDocument

		Try

			' Load the XML response into an XML Document and return it.
			doc.LoadXml(readSource(submitPath + "&longUrl=" + url))
			Return doc

		Catch e As Exception

			Return New XmlDocument()
		End Try
	End Function


	' Fetches a result from bit.ly provided the URL submitted
	Private Function readSource(ByVal url As String) As String
		Dim client As New WebClient

		Try

			Using reader As New StreamReader(client.OpenRead(url))
				' Read all of the response
				Return reader.ReadToEnd()
				reader.Close()
			End Using

		Catch e As Exception
			Throw e
		End Try

	End Function

End Class

The class is made up of two constructors. One which takes no parameters (providing defaults) and another which takes two parameters representing the login account and API key provided by bit.ly (if you signed up for an account with them). Either way this should work for you even if you don’t have an account. In addition to the constructors, we provide two properties that can be used to retrieve an error code and error message in the event that something terrible and horrible happens. You can use these to check and see what is going on. We also specify the shorten public method which is the main method of the class and takes in the long URL. When this method finished, it will provide the caller a short URL string returned by bit.ly.

There is a small supporting cast of private helper functions which take separate jobs of communicating with bit.ly, building an XmlDocument using the XML response returned from the bit.ly API and another to yank out any error codes and messages in the rare chance that any are found.

readSource() is responsible for connecting to the web source, getting a stream to the API, submitting our aggregated URL string and reading the XML using the ReadToEnd() method of the StreamReader class. It returns this string to the caller which is the buildDocument() method. This method is responsible for taking the XML source string, placing it into an XmlDocument class and parsing out the nodes using XPath. We are looking for the element “shortUrl” here to retrieve the short URL returned from bit.ly.

All this is also done in our C# version shown below…

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;

namespace bitly
{
	/// <summary>
	/// This class connects to bit.ly for URL shortening.
	/// 
	/// Class contains an overloaded constructor to take in a personal login and api key
	/// </summary>
  
	class bitly
	{
		private string loginAccount;
		private string apiKeyForAccount;
		private string submitPath = @"http://api.bit.ly/shorten?version=2.0.1&format=xml";
		private int errorStatus = 0;
		private string errorMessage = "";


		/// <summary>
		/// Default constructor which will login with demo credentials
		/// </summary>
		/// <returns>A bitly class object</returns>
		public bitly(): this("bitlyapidemo", "R_0da49e0a9118ff35f52f629d2d71bf07")
		{
			
		}


		/// <summary>
		/// Overloaded constructor that takes a bit.ly login and apikey (if applicable)
		/// </summary>
		/// <returns>A bitly class object</returns>
		public bitly(string login, string APIKey)
		{
			loginAccount = login;
			apiKeyForAccount = APIKey;

			submitPath += "&login=" + loginAccount + "&apiKey=" + apiKeyForAccount;
		}


		// Properties to retrieve error information.
		public int ErrorCode
		{
			get { return errorStatus; }
		}

		public string ErrorMessage
		{
			get { return errorMessage; }
		}


		/// <summary>
		/// Shortens a provided URL
		/// </summary>
		/// <param name="url">A URL</param>
		/// <returns>A shortened bit.ly URL String</returns>
		public string shorten(string url)
		{
			errorStatus = 0;
			errorMessage = "";

			XmlDocument doc = buildDocument(url);

			if (doc.DocumentElement != null)
			{
				XmlNode shortenedNode = doc.DocumentElement.SelectSingleNode("results/nodeKeyVal/shortUrl");

				if (shortenedNode != null)
				{
					return shortenedNode.InnerText;
				}
				else
				{
					errorCode(doc);
				}
			}
			else
			{
				this.errorStatus = -1;
				this.errorMessage = "Unable to connect to bit.ly for shortening of URL";
			}

			return "";

		}


		// Sets error code and message in the situation we receive a response, but there was
		// something wrong with our submission.
		private void errorCode(XmlDocument doc)
		{
			XmlNode errorNode = doc.DocumentElement.SelectSingleNode("errorCode");
			XmlNode errorMessage = doc.DocumentElement.SelectSingleNode("errorMessage");

			if (errorNode != null)
			{
				this.errorStatus = Convert.ToInt32(errorNode.InnerText);
				this.errorMessage = errorMessage.InnerText;
			}
		}
		   
	 
		// Builds an XmlDocument using the XML returned by bit.ly in response 
		// to our URL being submitted
		private XmlDocument buildDocument(string url)
		{
			XmlDocument doc = new XmlDocument();

			try
			{
				// Load the XML response into an XML Document and return it.
				doc.LoadXml(readSource(submitPath + "&longUrl=" + url));
				return doc;
			}
			catch (Exception e)
			{
				return new XmlDocument();
			}
		}


		// Fetches a result from bit.ly provided the URL submitted
		private string readSource(string url)
		{
			WebClient client = new WebClient();

			try
			{
				using (StreamReader reader = new StreamReader(client.OpenRead(url)))
				{
					// Read all of the response
					return reader.ReadToEnd();
					reader.Close();
				}
			}
			catch (Exception e)
			{
				throw e;
			}
		}
	}
}

As you can see this is almost identical to the VB.NET version but with the minor syntax changes. Again we open up our connection, retrieve the string XML response, parse that XML using XPath and return the shortUrl element’s data to the caller. We could then use this class as we would for any class anywhere in the project. Place it in the button and use code similar to…

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
		Dim b As New bitly

		MessageBox.Show(b.shorten("http://www.cnn.com"))
End Sub

Not too bad huh? With this nifty little class you can quickly and easily use it to build applications which may need to submit URL’s for shortening. Perhaps your own twitter client or for anything that would need simple URL’s instead of long ones. Have fun playing and tinkering with this code. It is in the public domain, as all code on the Programming Underground is, so if a five finger discount is your specialty… enjoy! Thanks for reading! 🙂

About The Author

Martyr2 is the founder of the Coders Lexicon and author of the new ebooks "The Programmers Idea Book" and "Diagnosing the Problem" . He has been a programmer for over 25 years. He works for a hot application development company in Vancouver Canada which service some of the biggest tech companies in the world. He has won numerous awards for his mentoring in software development and contributes regularly to several communities around the web. He is an expert in numerous languages including .NET, PHP, C/C++, Java and more.