Skip to content

Instantly share code, notes, and snippets.

@davidsnyder
Created December 17, 2011 20:18
Show Gist options
  • Save davidsnyder/1491244 to your computer and use it in GitHub Desktop.
Save davidsnyder/1491244 to your computer and use it in GitHub Desktop.
Factual V3 API Wrapper

Factual API Wrapper

The ruby-factual gem is clunky and out of date, so I tossed together a script to access the new v3 API.

The v3 Factual API encourages 2-legged OAuth for requests. Request a key here:

http://developer.factual.com/display/docs/Factual+Developer+APIs+Version+3

require 'factual'

client = Factual::Client.new(OAUTH_KEY,OAUTH_SECRET)

client.table("places").q("burger").near({"$circle"=>{"$center"=>[30.3,-97.7],"$meters"=>5000}}).limit(1).fetch

=> {"version"=>3, "status"=>"ok", "response"=>{"data"=>[{"factual_id"=>"cca4257e-31fa-4c36-bfe0-12497557a62b", "name"=>"Hill-Bert's Burgers Too", "address"=>"5340 Cameron Rd", "locality"=>"Austin", "region"=>"TX", "country"=>"US", "postcode"=>"78723", "tel"=>"(512) 371-3717", "category"=>"Food & Beverage > Restaurants", "website"=>"http://hill-bertsburgers.com/", "latitude"=>30.3116, "longitude"=>-97.706703, "status"=>"1", "$distance"=>1441.4647}], "included_rows"=>1}}

Parameters are specified just as they are in the docs:

http://developer.factual.com/display/docs/Core+API+-+Read

As used above, geo is aliased as near.

Gem::Specification.new do |s|
s.name = 'factual'
s.version = '0.0.1'
s.platform = Gem::Platform::RUBY
s.author = 'David Snyder'
s.email = 'david@democraticlunch.com'
s.summary = 'Factual V3 API Wrapper'
s.description = 'Wrapper for the Factual V3 API (http://www.factual.com/)'
s.files = ['factual.rb']
s.require_path = '.'
s.add_dependency('yajl-ruby')
s.add_dependency('oauth')
end
require 'oauth'
require 'yajl'
module Factual
class Client
attr_reader :access_token,:filters,:sort,:query,:offset,:select,:limit,:geo,:include_count,:table,:action
def initialize(oauth_key,oauth_secret)
@include_count = false
consumer = OAuth::Consumer.new(oauth_key,oauth_secret,:site => 'http://api.v3.factual.com/')
@access_token = OAuth::AccessToken.new(consumer)
end
def filters(filters)
@filters = filters
self
end
def include_count(bool=true)
@include_count = bool
self
end
def sort(sort_options)
@sort = sort_options
self
end
def select(fields)
@select = fields
self
end
def limit(limit)
@limit = limit
self
end
def geo(filters)
@geo = filters
self
end
alias_method :near, :geo
def offset(offset)
@offset = offset
self
end
def q(query)
@query = query
self
end
alias_method :search,:q
def table(table)
@table = table
self
end
#method - @schema@ or @read@
def action(method="read")
@action = method
self
end
def url
[url_base,query_string].join("")
end
def fetch
response = @access_token.request(:get,url)
Yajl::Parser.parse(response.body)
end
private
def url_base
raise "Table name or id unspecified" unless @table
action unless @action
access_token.consumer.options[:site]+["t",@table,@action].map{|ele| ele }.join("/") + "?"
end
def query_values
[@filters,@sort,@query,@offset,@select,@limit,@geo,@include_count]
end
def query_keys
["filters","sort","q","offset","select","limit","geo","include_count"]
end
def query_string
query_str = query_keys.zip(query_values)
query_str.reject{|arr| arr[1].nil? || (arr[1].respond_to?(:empty?) && arr[1].empty?) }.map{|arr| arr[1] = Yajl::Encoder.encode(arr[1]) if %w(geo filters).include?(arr[0]);[arr[0],OAuth::Helper.escape(arr[1])].join("=") }.join("&")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment