Introducing the Evri Cocoa API

Now that we’ve gotten version 2.0 of EvriVerse in the App Store, it’s time to talk about some of its internals. In this post we’re going to talk about how EvriVerse works with our public API using our open-source Cocoa library. While the library code isn’t specific to the iPhone, the Xcode project that it is part of has a definite iPhone bent to it. Eventually we’ll enhance it to build a Mac OS framework. For now it has been somewhat purpose-built as a static library for iPhone applications.

Using the EvriApi

Using the API starts with creating an instance of the EvriApi class. When you create one you need to provide an application identifier.

EvriApi *api = [[EvriApi alloc] initWithAppID:@"My-Awesome-Evri-Powered-App"];

Right now we aren’t using API keys, but we would appreciate it if you could put some short descriptive text here so we can differentiate between requests when we analyze our API logs.

You only need one instance of this class (it’s thread-safe) so you should keep a reference to it in some globally-available place such as your application delegate class.

The EvriApi is designed for maximum UI responsiveness. Instead of blocking callers until results are returned from our web API, requests are made with a target object and a specific method selector. When the request completes, the callback method will be invoked on the specified target asynchronously. This keeps your main thread of control from blocking which can lead to a lousy user-experience. All of the API-related methods on the EvriApi class implement a signature like:

// assume we have the method -handleCallback:(EvriApiResponse *)response
NSString *requestID = [api makeRequestForSomething:@"A Thing"
                                   performSelector:@selector(handleCallback:)
                                          onTarget:self];

The callback method will be handed an EvriApiResponse instance which can be queried for success and for the message payload:

- (void)handleCallback:(EvriApiResponse *)response {
  if ([response success]) {
    NSArray *entities = (NSArray *)[response responseObject];
    // do cool stuff with entities
  }
  else {
    // handle error case
  }
}

When making a request, it immediately returns a unique request identifier as a string. You can use this to cancel any outstanding requests if the user switches views before the request completes. OK, enough Cocoa details, let’s dig into the APIā€¦

Using the API

Newsmakers

So let’s dig in by starting with our new startup screen. Instead of starting with the graph view, we now give you a view of the top newsmakers as we show them on our homepage. This is done by calling the -fetchPopwhyList:withSelector:onTarget: method. The callback method will be delivered an array of PopwhyItems, which are just simple model objects. We use each entry to fill out the table cells in this view, except for the images which are retrieved asynchronously.

photo 4.jpg

The Graph View

Once an entity is selected from the previous screen, we make a call to -fetchTopTargetsForEntity:performSelector:onTarget:. This call will asynchronously deliver an array of Entity objects to the callback method. In EvriVerse we take the top five surrounding entities and render the graph view like so:

photo 5.jpg

Whenever a user touches one of the target entities, we simply re-issue the same query with a different entity URI and rebuild the graph on the callback. Because the results are delivered asynchronously it was easy to split our animations up into changes that execute concurrently with the request (shrinking down nodes we’re going to throw away) and animations that occur after we have received the query results (growing the new nodes).

Note that the Entity objects returned by this call are not fully “fleshed-out”. If you want additional details you need to query the API for them (explained below).

Entity Headlines

On the main entity in the graph view, the user can select one of four sub-views. The first one is the headlines view. Here we request top news articles for an entity like so:

NSString *reqID = [api fetchArticlesForEntity:@"/person/les-paul-0x182c4"
                              performSelector:@selector(handleNews:)
                                     onTarget:self];

The callback method will receive an array of Article objects which contain the headline, a snippet of relevant text and the original URI.

photo 3.jpg

When a user selects one of these articles, we simply push a web view into view with the original article URL as the content source.

Entity Images

One of the new features we’ve added in the 2.0 release of EvriVerse is the ability to browse recent images for the selected entity. To retrieve images for a given entity URI, make a call like this:

NSString *reqID = [api fetchImagesForEntity:@"/person/jimmy-page-0x35793"
                            performSelector:@selector(handleEntityImages:)
                                   onTarget:self];

The callback method will receive an array of ImageData model objects. Note that these objects only contain the URLs for the images, not the image data itself.

photo-1.jpg

Images are associated with their original source, so when a user touches an image we push a web view with the original web page as the source.

Entity Profile

Sometimes you just want to know who or what a particular entity is. This view provides some high-level details to answer that question such as an image, and a description.

photo.jpg

To get this kind of information you can call the API like so:

NSString *reqID = [api fetchEntityDetails:@"/person/les-paul-x182c4"
                          performSelector:@selector(handleEntityDetails:)
                                 onTarget:self];

The callback method will return a fleshed-out Entity object.

Entity Connections

The last view in our tour of the EvriVerse application is the entity connections view. This is one of the things that really sets Evri apart from other news applications. The connections listed in this view are always up to date based on what’s going on in the news.

photo 2.jpg

In this example we can see a number of other musicians related to the late, great Les Paul. These connections are culled from the vast array of sources we index on the web. Over time these connections change based on what people are writing about on the web.

To get this information, call the API like this:

NSString *reqID = [api fetchTopTargetsForEntity:@"/person/les-paul-0x182c4"
                                performSelector:@selector(handleRelatedEntities:)
                                       onTarget:self];

The callback method will receive an array of Target objects which contain a URI describing the relationship and the other Entity. We use this information to render the table view above.

photo 2-1.jpg

When a user selects one of these connected entities we want to display a list of articles constrained to those two items. For example, selecting “Jimmy Page” will return us a list of articles that contains articles with sentences connecting Les Paul with Jimmy Page. To get this information call the API like so:

NSString *reqID = [api fetchArticlesForEntity:@"/person/les-paul-0x182c4"
                                  otherEntity:@"/person/jimmy-page-0x35793"
                              performSelector:@selector(handleArticles:)
                                     onTarget:self];

The callback method will receive an array of Article model objects.

EvriVerse is just one of what will be many ways that we wrap our public API into a compelling user-experience. With the release of EvriApi under an open-source license we are excited to see what other developers do with it. So go get the library, build something cool and wow us!

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

2 Comments

Leave Comment