Initialize an object from an external API
There is a number of external APIs, which provide data over XML or JSON. For example, BART system API http://api.bart.gov/docs/overview/index.aspx. This gem is to designed to load the external API data into a set of nested Ruby objects.
Installation
gem install api_object
Usage
Example - BART train departure estimate
1) Subclass your objects from ActiveApi::ApiObject
class Station < ActiveApi::ApiObject
end
class Estimate < ActiveApi::ApiObject
end
class Station < ActiveApi::ApiObject
end
2) Specify the url to load the data from, optionally an action and a mode, an api key and parameters(options) for the url; such as the url would look like "http://<api_url>/<action>?
This will be defined in the upper object over the function "initialize_from_api". Options for this function:
:url - specify url
:action - specify action
:mode - specify mode (such as 'verbose', 'terse' etc.)
:key - api key
:data_tags - specify tag parameters under which object data might be stored, for example <location value='San Francisco'/> - "value" would be a data tag. :data_tags accepts a single value or an array.
:url_options - parameters
The following is designed to generate real time departure estimates for BART stations:
class Station
initialize_from_api :url => "http://api.bart.gov/api/", :action => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
end
In this example, the url generated to get real time departure estimates from the Richmond station will be: http://api.bart.gov/api/etd.aspx?cmd=etd&orig=RICH&key=MW9S-E7SL-26DU-VV8V
3) Define class attributes and mapping of the attributes to the api where the api name is different. To define api simple type mappings, use "api_column <attribute name>, <api attribute name>". To define api association mapping, use "api_association <association attribute name>, <api attribute name>, :as => <association class name>". Either the second, or the third parameters could be omitted. If the third parameter is omitted, it's mapped to the class name by the attribute name defined in the class.
In the following example, a simple attribute name is "abbreviation", but the name defined in the api XML documents is "abbr". An association is defined in the attribute :est, the api mapping is :etd and it's an object of the class Estimate.
class Station < ActiveApi::ApiObject
initialize_from_api :url => "http://api.bart.gov/api/", :action => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
attr_reader :name, :abbreviation, :date, :time, :est
api_column :abbreviation, :abbr
api_association :est, :etd, :as => Estimate
end
4) To load api data into an object, use the class method "get_results(options)". In the example, get real time estimates for the station Glen Park.
data = Station.get_results(:orig => 'GLEN')
Please, note that data loaded might be either a hash, or an array of hashes, depending on the api.
5) Create an object from the data
If the example, the data received is a hash, so create an object.
station = Station.new(data)
If the data is an array of hashes, then it might be used to create an array of objects
stations = data.map {|d| Station.new(d)}
6) Getting location based data by ip.
A) Getting location using ipinfodb.com (requires api key)
This gem uses geo_ip gem and ipinfodb.com webservice to retrieve location based on ip.
The service requires an API key, in order to get it register at the web site.
The geo_ip gem retrieves location as:
{
:status_code => "OK",
:status_message => "",
:ip => "209.85.227.104"
:country_code => "US",
:country_name => "UNITED STATES",
:region_name => "CALIFORNIA",
:city => "MONTEREY PARK",
:zip_code => "91754",
:latitude => "34.0505",
:longitude => "-118.13"
}
To get the data, call "get_results_by_ip" instead of "get_results":
data = Weather.get_results_by_ip('99.156.82.20', :key => <KEY>, :weather => :zip_code)
The function takes parameters to define what fields from the location object are passed as what parameter. In this case, "zip_code" field is passed as "weather" parameter and the original function is:
data = Weather.get_results(:weather => '99.156.82.20')
This service is allowed to be used only for internal business purposes. Please, verify with the Terms and Conditions when registering for a key.
B) Getting location using freegeoip.net (requires no key)
As the ipinfodb.com service has limitations in the terms of use, the gem freegeoip gem is used whenever no api key is provided. Unfortunatelly, their database last update was April 29, 2011.
The freegeoip gem retrieves location as:
{
"city" => "Round Rock"
"region_code" => "TX"
"region_name" => "Texas"
"metrocode" => "635"
"zipcode" => "78681"
"longitude" => "-97.7286"
"latitude" => "30.5321"
"country_code" => "US"
"ip" => "99.156.82.20"
"country_name" => "United States"
}
To get the data, call "get_results_by_ip" instead of "get_results":
data = Weather.get_results_by_ip('99.156.82.20', :weather => :zipcode)
The function takes parameters to define what fields from the location object are passed as what parameter. In this case, "zipcode" field is passed as "weather" parameter and the original function is:
data = Weather.get_results(:weather => '99.156.82.20')
7) Error handling
In case data cannot be retrived (possible causes might be a wrong url or service downtime), the object returned is empty. Error messages could be checked using functions errors and has_errors?
station.has_errors?
errors = station.errors
8) Testing
The gem has been tested on BART, Google Weather and NextBus APIs.
To run tests by ip location for ipinfodb.com service, please, register for an API key.
The key should be either placed into the test/data/keys/ipinfodb_key.txt file or passed as an environment variable:
API_KEY='<your key>' rake test
There is no existing api key provided with this gem as per the Terms and Conditions of the ipinfodb service.
If there is no key provided, those tests will be avoided.
9) Limitations
- Api data must be presented either in XML or in JSON format. The distinction between XML and JSON is determinted automatically.
- Location by ip service uses a free database which is not always reliable.
- When using this gem with external APIs, check Terms and Conditions of the API usage.
- If something is not working, feel free to submit bugs and or/contribute.
Compatibility
Ruby 1.9.3
License
MIT License. Copyright 2012 TJ Moskun.