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! 🙂