Download - JSON and the APInauts
![Page 1: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/1.jpg)
JSON AND THE ARGONAUTSAPI
WYNNNETHERLAND
![Page 2: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/2.jpg)
whoami
![Page 4: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/4.jpg)
![Page 5: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/5.jpg)
I write API wrappersA lot of API wrappers!
![Page 6: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/6.jpg)
& more!
![Page 7: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/7.jpg)
Why create API wrappers?
![Page 8: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/8.jpg)
After all, we have
![Page 9: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/9.jpg)
curl
![Page 10: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/10.jpg)
curl http://api.twitter.com/1/users/show.json?screen_name=pengwynn
![Page 11: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/11.jpg)
Net::HTTP
![Page 12: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/12.jpg)
url = "http://api.twitter.com/1/users/show.json?screen_name=pengwynn"Net::HTTP.get(URI.parse(url))
![Page 13: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/13.jpg)
Because we're Rubyists, and we want
![Page 14: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/14.jpg)
Idiomatic access
![Page 15: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/15.jpg)
{"chart":{ "issueDate":2006-03-04, "description":"Chart", "chartItems":{ "firstPosition":1, "totalReturned":15, "totalRecords":25663, "chartItem":[{ "songName":"Lonely Runs Both Ways", "artistName":"Alison Krauss + Union Station", "peek":1, "catalogNo":"610525", "rank":1, "exrank":1, "weeksOn":65, "albumId":655684, ... }}
![Page 16: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/16.jpg)
{"chart":{ "issueDate":2006-03-04, "description":"Chart", "chartItems":{ "firstPosition":1, "totalReturned":15, "totalRecords":25663, "chartItem":[{ "songName":"Lonely Runs Both Ways", "artistName":"Alison Krauss + Union Station", "peek":1, "catalogNo":"610525", "rank":1, "exrank":1, "weeksOn":65, "albumId":655684, ... }}
![Page 17: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/17.jpg)
Rubyified keys
![Page 18: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/18.jpg)
{"chart":{ "issueDate":2006-03-04, "description":"Chart", "chartItems":{ "firstPosition":1, "totalReturned":15, "totalRecords":25663, "chartItem":[{ "songName":"Lonely Runs Both Ways", "artistName":"Alison Krauss + Union Station", "peek":1, "catalogNo":"610525", "rank":1, "exrank":1, "weeksOn":65, "albumId":655684, ... }}
![Page 19: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/19.jpg)
{"chart":{ "issue_date":2006-03-04, "description":"Chart", "chart_items":{ "first_position":1, "total_returned":15, "total_records":25663, "chart_item":[{ "song_name":"Lonely Runs Both Ways", "artist_name":"Alison Krauss + Union Station", "peek":1, "catalog_no":"610525", "rank":1, "exrank":1, "weeks_on":65, "album_id":655684, ... }}
![Page 20: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/20.jpg)
... and method names
![Page 21: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/21.jpg)
# Retrieve the details about a user by email# # +email+ (Required)# The email of the user to look within. To run getInfoByEmail on multiple addresses, simply pass a comma-separated list of valid email addresses.# def self.info_by_email(email) email = email.join(',') if email.is_a?(Array) Mash.new(self.get('/', ! ! :query => {! ! ! :method => 'user.getInfoByEmail', ! ! ! :email => email }.merge(Upcoming.default_options))).rsp.userend
![Page 22: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/22.jpg)
# Retrieve the details about a user by email# # +email+ (Required)# The email of the user to look within. To run getInfoByEmail on multiple addresses, simply pass a comma-separated list of valid email addresses.# def self.info_by_email(email) email = email.join(',') if email.is_a?(Array) Mash.new(self.get('/', ! ! :query => {! ! ! :method => 'user.getInfoByEmail', ! ! ! :email => email }.merge(Upcoming.default_options))).rsp.userend
More Ruby like than
![Page 23: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/23.jpg)
SYNTACTIC SUGAR
![Page 24: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/24.jpg)
Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch()
![Page 25: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/25.jpg)
Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch()
Method chaining
![Page 26: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/26.jpg)
stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores
![Page 27: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/27.jpg)
stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores
Method chaining
![Page 28: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/28.jpg)
client.statuses.update.json! :status => 'this status is from grackle'
![Page 29: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/29.jpg)
client.statuses.update.json! :status => 'this status is from grackle'
Method chaining Bang for POST
![Page 30: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/30.jpg)
APPROACHES
![Page 31: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/31.jpg)
Simple Wrapping
![Page 32: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/32.jpg)
SOME TWITTER EXAMPLESTwitter Auth from @mbleighuser.twitter.post('/statuses/update.json', 'status' => 'Tweet, tweet!'
)
Grackle from @hayesdavisclient.statuses.update.json! :status => 'Tweet, tweet!'
Twitter from @jnunemaker client.update('Tweet, tweet!')
Wrapping
Wrapping... with style
Abstraction
![Page 33: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/33.jpg)
Why simply wrap?
![Page 34: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/34.jpg)
Insulate against change
![Page 35: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/35.jpg)
Leverage API documentation
![Page 36: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/36.jpg)
Why abstract?
![Page 37: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/37.jpg)
...or writing APIs to wrap APIs
![Page 38: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/38.jpg)
Simplify a complex API
![Page 39: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/39.jpg)
Provide a business domain
![Page 40: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/40.jpg)
TOOLS
![Page 41: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/41.jpg)
Transports
![Page 42: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/42.jpg)
Net::HTTP
![Page 43: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/43.jpg)
Patronhttp://toland.github.com/patron/
![Page 44: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/44.jpg)
Typhoeushttp://github.com/pauldix/typhoeus
![Page 45: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/45.jpg)
em-http-requesthttp://github.com/igrigorik/em-http-request
![Page 46: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/46.jpg)
Parsers
![Page 47: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/47.jpg)
Crack
Puts the party in HTTParty
http://github.com/jnunemaker/crack
![Page 48: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/48.jpg)
JSON
![Page 49: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/49.jpg)
yajl-rubyhttp://github.com/brianmario/yajl-ruby
![Page 50: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/50.jpg)
multi_jsonhttp://github.com/intridea/multi_json
![Page 51: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/51.jpg)
Higher-level libraries
![Page 52: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/52.jpg)
HTTParty
When you HTTParty, you must party hard!
http://github.com/jnunemaker/httparty
![Page 53: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/53.jpg)
HTTParty- Ruby module - GET, POST, PUT, DELETE - basic_auth, base_uri, default_params, etc.
- Net::HTTP for transport- Crack parses JSON and XML
![Page 54: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/54.jpg)
HTTPartyclass Delicious include HTTParty base_uri 'https://api.del.icio.us/v1' def initialize(u, p) @auth = {:username => u, :password => p} end
...
def recent(options={}) options.merge!({:basic_auth => @auth}) self.class.get('/posts/recent', options) end
...
![Page 55: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/55.jpg)
monster_mashhttp://github.com/dbalatero/monster_mash
HTTParty for Typhoeus, a monster. Get it?
![Page 56: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/56.jpg)
RestClienthttp://github.com/adamwiggins/rest-client
![Page 57: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/57.jpg)
RestClient- Simple DSL- ActiveResource support- Built-in shell
RestClient.post(! 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' })
![Page 58: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/58.jpg)
Wearyhttp://github.com/mwunsch/weary
![Page 59: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/59.jpg)
Weary- Simple DSL- Specify required, optional params- Async support
![Page 60: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/60.jpg)
Wearydeclare "foo" do |r| r.url = "path/to/foo" r.via = :post r.requires = [:id, :bar] r.with = [:blah] r.authenticates = false r.follows = false r.headers = {'Accept' => 'text/html'}end
client.foo :id => 123, :bar => 'baz'
becomes
![Page 61: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/61.jpg)
RackClienthttp://github.com/halorgium/rack-client
![Page 62: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/62.jpg)
RackClient- Rack API- Middleware!
client = Rack::Client.new('http://whoismyrepresentative.com')
![Page 63: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/63.jpg)
Faradayhttp://github.com/technoweenie/faraday
![Page 64: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/64.jpg)
Faraday- Rack-like- Middleware!- Adapters
![Page 65: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/65.jpg)
Faradayurl = 'http://api.twitter.com/1'conn = Faraday::Connection.new(:url => url ) do |builder| builder.adapter Faraday.default_adapter builder.use Faraday::Response::MultiJson builder.use Faraday::Response::Mashifyend
resp = conn.get do |req| req.url '/users/show.json', :screen_name => 'pengwynn'end
u = resp.bodyu.name# => "Wynn Netherland"
![Page 66: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/66.jpg)
Faraday Middlewarehttp://github.com/pengwynn/faraday-middleware
![Page 67: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/67.jpg)
Faraday Middleware- Hashie- Multi JSON- OAuth, OAuth2 as needed
![Page 68: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/68.jpg)
My current stack- Faraday- Faraday Middleware - Hashie - Multi JSON- OAuth, OAuth2 as needed
![Page 69: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/69.jpg)
Hashie- Mash- Dash- Trash- Clash
![Page 71: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/71.jpg)
HTTPScoop
![Page 72: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/72.jpg)
Charles Proxy
If you have an iOS app, you have an API ;-)
![Page 73: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/73.jpg)
Testing
![Page 74: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/74.jpg)
Fakewebhttp://github.com/chrisk/fakeweb
![Page 75: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/75.jpg)
VCRhttp://github.com/myronmarston/vcr
![Page 76: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/76.jpg)
Artifice
Artifice.activate_with(rack_endpoint) do # make some requests using Net::HTTPend
a @wycats joint
http://github.com/wycats/artifice
![Page 77: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/77.jpg)
ShamRackhttp://github.com/mdub/sham_rack
![Page 78: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/78.jpg)
ShamRackShamRack.at("sinatra.xyz").sinatra do get "/hello/:subject" do "Hello, #{params[:subject]}" endend
open("http://sinatra.xyz/hello/stranger").read
#=> "Hello, stranger"
![Page 79: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/79.jpg)
ShamRackShamRack.at("rackup.xyz").rackup do use Some::Middleware use Some::Other::Middleware run MyApp.newend
Rack 'em up!
![Page 80: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/80.jpg)
Authentication
![Page 81: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/81.jpg)
Basic
![Page 83: JSON and the APInauts](https://reader034.vdocuments.us/reader034/viewer/2022051515/54c836ea4a7959aa1e8b45a2/html5/thumbnails/83.jpg)
OAuth2http://github.com/intridea/oauth2