avail.io Front End

A simple JSON example

Availio.fe is a native Mac client I wrote for the avail.io domain-search api. Originally developed for mobile web clients by Jonathan Stark and Kelli Shaver of nitch.cc fame, the avail.io API provides a web back-end service for domain-search. I wrote a Mac client for avail.io primarily as an exercise to familiarize myself with handling JSON within Cocoa.

This program demonstrates a simple example of handling JSON requests between a Mac and a web api. Inspirational credits go to Ray Wenderlic and his awesome iOS 5 tutorial website.

The Code

You can find this source in Xcode project format on github. Following is a short explanation of what’s going on in the source.

Let’s start with a screen shot of the app which we’ll make reference to later.

screen shot of avail.io front end

And now a look under the hood.

We start by defining a couple of consonants to make life easier.

// define a constant for a background queue
    #define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
    // define a constant for the avail.io URL
    #define kAvailioApiURL [NSURL URLWithString: @"http://api.avail.io/"]

The first define is for a background queue which we’ll see used later in a block call to the avail.io api. Next is our define for the avail.io api URL.

When the find button is clicked we’ll make the call to the avail.io URL with our search term appended onto the end. The URL would look like this if you saw it in a browser: http://avail.io/ourSearchTerm. The top most text view in our window is where the user will input our search term. You’ll see this referenced in later code as domainSearchTerm. On the other hand domainSearchResults is our second (bottom) text view of our interface. This is where we’ll display our feedback to the user.

The dispatch_async block invocation (see below) sets up our thread which goes off on it’s own to send the query to avail.io and patiently wait for the returned JSON data. As soon as the data is returned, the fetchedData method referenced via @selector is subsequently invoked.

- (IBAction)findDomain:(NSButton *)sender {
        domainSearchResults.string = [NSString stringWithFormat:@"Querying for available domains based on %@.n", domainSearchTerm.stringValue];
        // make the call to avail.io to get the JSON
        dispatch_async(kBgQueue, ^{ 
            NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString:domainSearchTerm.stringValue relativeToURL: kAvailioApiURL]];
            [self performSelectorOnMainThread:@selector(fetchedData:) 
                                   withObject:data waitUntilDone:YES];
        });
 
    }

The Data

Here’s a sample of what the data we (hope to) get back from avail.io should look like.

{
    {
    "admin_contact" = "ALLSMILES.TV@domainsbyproxy.com";
    available = 0;
    domain = "allsmiles.tv";
    "expires_on" = "2013-05-30 00:00:00 +0000";
    registrars =         (
                    {
            name = NameCheap;
            shortlink = "http://avail.io/go/l42it";
            url = "http://www.namecheap.com/domains/domain-name-search/results.aspx?domain=allsmiles.tv&tlds=&searchall=&type=single&";
        },
                    {
            name = GoDaddy;
            shortlink = "http://avail.io/go/hu01s";
            url = "http://www.godaddy.com/domains/search.aspx?checkAvail=1&domainToCheck=allsmiles.tv";
        },
                    {
            name = Hover;
            shortlink = "http://avail.io/go/4yc1h";
            url = "https://www.hover.com/domains/results?q=allsmiles.tv";
        }
    );
    tld = tv;
}

So, with JSON now in hand so to speak, we are ready to display the results to the user right? Uhhhmmm, that is, if everything went well with the call above to fetch the JSON data. We can’t just assume it did :D though. Fortunately, Cocoa makes error checking pretty easy.

NSError* error sets up an object for error reporting. See the class reference in the Apple developer documentation for all the rich properties this class provides. What I like best about using NSError is it let’s me avoid the indentation hades of try/catch which I’ve never warmed to. A simple test of the response data object against nil and we’re continuing on our way.

Next we get our JSON data into an NSArray using objectForKey:@”response” (see the HappyDocs documentation for the returned JSON object).

- (void)fetchedData:(NSData *)responseData {
        //parse out the json data
        NSString* availability;
        NSError* error = nil;
        NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData                         
                                                             options:kNilOptions 
                                                               error:&error];
 
        // make sure we got something, otherwise error out
        if (!json) {
            domainSearchResults.string = @"%@: Error retrieving results: %@", [self class], [error localizedDescription];
            return;
        }
 
        // ok, should be safe to proceed with parsing
        NSArray* jsonReturned = [json objectForKey:@"response"];
        //NSLog(@"JSON returned: %@", jsonReturned);
 
        // loop through the JSON results
        for (NSDictionary* mostRecentDomain in jsonReturned) {
 
            // get the mostRecentDomain availablility
            NSNumber* available = [mostRecentDomain objectForKey:@"available"];
 
            // test availability and display results accordingly
            if ([available integerValue] == 1){
                availability = @"YES";
            } else {
                availability = @"NO";
            }
            // append this domain and availability to the text view
            domainSearchResults.string = [NSString stringWithFormat:@"%@n%@ttavailable = %@", domainSearchResults.string,[mostRecentDomain objectForKey:@"domain"], availability];
        }// end for-in loop through jsonReturned
    }

Using objective-c’s for in loop syntax we can adopt Fast Enumeration and quickly iterate through NSDictionary’s keys. Using Fast Enumeration is much more efficient than using NSEnumerator directly. Along the way we test the value for the available key which tells us if a particular domain is available to be registered or not.

Then pack everything in one quick and dirty NSString for text view display purposes (and for the purposes of finishing this project before my deadline) and we’re done!

JSON was articulated in order to trim off the fat and verbosity of XML and it achieves that goal admirably. Cocoa’s JSON handling capabilities are equally light and easy to use.