Saturday, June 18, 2016

Ridiculously Easy Autocomplete with the EveKit Online SDE

If you don't know already, here at Orbital Enterprises we host the two most recent versions of the EVE Online Static Data Export as a web service.  I posted about this previously here.

As I mention in the original blog post, the online SDE is mostly useful for short queries or lookups, and isn't the best thing for complicated queries (e.g. things that would end up being complicated joins if you had direct access to the database).  However, for web developers out there, it turns out to be ridiculously easy to implement nice features like EVE type name auto-completion using the online SDE.  I'll show you how to do that using javascript in this blog entry.

Resources

EveKit SDE Public Site
GitHub Project Page
Sample Code

Annotated Example

You can download the sample file (auto.html) from the link above.  You should be able to point your browser to a local copy of the sample and auto-complete EVE type names in the text box.  We'll go over the important parts of the sample file below.

We start out by loading a few important libraries in the header:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>autocomplete demo</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
  <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
  <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
  <script src='https://cdn.rawgit.com/swagger-api/swagger-js/master/browser/swagger-client.min.js' type='text/javascript'></script>
</head>
<body>

We use jQuery's auto-completion support to drive our flow.  You don't have to use jQuery to do this; there are other javascript libraries that support auto-completion.  In fact, all you really need is something that will accept text and periodically query an auto-completion routine to return possible choices.  But jQuery is one of the easiest to use, so that's what we use here.

We also load the Swagger javascript client library.  This library will turn the online SDE API spec into a usable javascript client.  We talk about Swagger all the time with EveKit because all our APIs are annotated with Swagger, making it very easy to build clients for our tools.  See some of our other posts for more detail on this topic.

There are two important bits of code in the sample file.  The first is the code which builds the Swagger client:

var url = "https://evekit-sde.orbital.enterprises/20160531/api/ws/v20160531/swagger.json";
var swagger = new SwaggerClient({
    url: url,
    usePromise: true
}).then(function(obj) {
    // save a debug copy of swagger as well as returning
    window.swagger = obj;
    console.log("swagger ready");
    $( "#typecomplete" ).autocomplete({ source: typeRequester });
    return obj;
}).catch(function(error) {
    console.error('Swagger promise rejected', error);
    return null;
});

The SwaggerClient class comes from the Swagger javascript library and is parameterized with a URL pointing to the location of the online SDE API specification.  In this example, we're using the most recent SDE at time of writing.  This will change over time, so be sure to visit the SDE page on a regular basis to get the latest URL.

The calling style used here is based on "promises" (and is initiated by passing the "usePromise: true" flag to Swagger).  Promises are a very clean approach to handling the asynchronous nature of remote calls in javascript.  You can read a very accessible introduction to promises here.  But even if you've never seen promises before, it's easy to intuit how the code works here: first we create the SwaggerClient object with an appropriate URL; THEN we save the result of that call and initialize the type completer; if something goes wrong, we CATCH the error and do something appropriate.

So the net result of this call is that we'll have an initialized text box and a Swagger client ready to retrieve data from the online SDE.  When the auto-completer is ready to attempt a completion, it calls the "typeRequest" function with the text the user has typed so far.  This is where we add the code to look up potential completions from the online SDE:

/* Support autocomplete of an EVE type */
var typeRequester = function(request, response) {
    // Query term uses SQL wildcards
    var queryTerm = '%' + request.term + '%';
    // Limit to 100 results for speed
    swagger.Inventory.getTypes({maxresults: 100, typeName: '{like: "' + queryTerm + '"}'})
.then(function(result) {
   var choices = [];
   for (var i = 0; i < result.obj.length; i++) {
choices.push(result.obj[i].typeName);
   }
   response(choices);
}).catch(function(error) {
   console.error("Swagger promise rejected", error);
   response([]);
});
};

According to the jQuery docs, the auto-completer will pass a "request" object with a "term" property containing the text entered by the user.  Any potential choices should be returned by invoking the "response" object, which will be a callback taking a list of choices.

To lookup potential matches, we use the "like" query support provided by the online SDE.  You can read more about this feature (and other query choices) here.  Essentially, we're constructing a SQL wildcard match of the form '%term%' and invoking the "getTypes" endpoint to collect potential matches.  We use the "promise" calling style again and populate an array of choices based on the returned type names.  If we catch an error, we return an empty list (the jQuery library requires that we always return a result, even if an error occurs).  We also limit the number of responses to make the auto-completion appear a bit snappier.

Parting Words

That's all there is to it!  The same pattern is usable with other SDE calls as well.  For example, you can create a "region auto-completer" by replacing "swagger.Inventory.getTypes" with "swagger.Map.getRegions" (and other naming changes, like replacing "typeName" with "regionName").  Hope this helps.  Happy coding!

Thursday, June 9, 2016

EveKit Updated for New XML API Endpoints

The Citadel release (April, 2016) of EVE Online added two new API endpoints as documented here.  These two new endpoints, Clones and Skills, provide access to a subset of the normal character sheet for a character.  You can therefore restrict an EVE XML API key to only provide access to these new endpoints.  If your key already provides access to the full character sheet, then there is no point authorizing these new endpoints as they add no new information.

We've added support for these new endpoints in EveKit for those of you who want to provide more restricted keys.  Since the data provided is a subset of the normal character sheet, we decided to just partially populate the current character sheet structure instead of introducing completely new EveKit model objects.

Here's how the synchronization works:

  1. We first check whether your API key allows character sheet synchronization.  If it does, then we sync the character sheet as usual and we're done.
  2. If character sheet synchronization isn't allowed, then we attempt to sync both Clones and Skills - whatever your API key happens to allow.  If your key allows neither of those endpoints, then we're done.
  3. If your key allows Clones, then your character sheet will be updated only on the fields provided by this endpoint (all of your clone information is updated, along with some attributes like race, bloodline, etc).
  4. If your key allows Skills, then the "free skill points" field of your character sheet is updated, as is your skill list (which we store in EveKit as separate model objects).
We haven't added any new EveKit access key settings for these new endpoints.  If your EveKit access key allows character sheet access, then you'll be able to see all the information updated by the Clones and Skills endpoints.