JSON and the APInauts
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

JSON and the APInauts

on

  • 9,729 views

Guide to writing great API wrappers in Ruby.

Guide to writing great API wrappers in Ruby.

Statistics

Views

Total Views
9,729
Views on SlideShare
9,726
Embed Views
3

Actions

Likes
23
Downloads
92
Comments
0

1 Embed 3

http://twitter.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

JSON and the APInauts Presentation Transcript

  • 1. API JSON AND THE ARGONAUTS WYNNNETHERLAND
  • 2. whoami
  • 3. +
  • 4. A lot of API wrappers! I write API wrappers
  • 5. & more!
  • 6. Why create API wrappers?
  • 7. After all, we have
  • 8. curl
  • 9. curl http://api.twitter.com/1/users/show.json?screen_name=pengwynn
  • 10. Net::HTTP
  • 11. url = "http://api.twitter.com/1/users/show.json?screen_name=pengwynn" Net::HTTP.get(URI.parse(url))
  • 12. Because we're Rubyists, and we want
  • 13. Idiomatic access
  • 14. {"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, ... }}
  • 15. {"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, ... }}
  • 16. Rubyified keys
  • 17. {"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, ... }}
  • 18. {"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, ... }}
  • 19. ... and method names
  • 20. # 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.user end
  • 21. # 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. # More Ruby like th an 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.user end
  • 22. SYNTACTIC SUGAR
  • 23. Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch()
  • 24. Method chaining Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch()
  • 25. stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores
  • 26. Method chaining stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores
  • 27. client.statuses.update.json! :status => 'this status is from grackle'
  • 28. Method chaining Bang for POST client.statuses.update.json! :status => 'this status is from grackle'
  • 29. APPROACHES
  • 30. Simple Wrapping
  • 31. SOME TWITTER EXAMPLES Twitter Auth from @mbleigh Wrapping user.twitter.post( '/statuses/update.json', 'status' => 'Tweet, tweet!' ) Wrapping... with style Grackle from @hayesdavis client.statuses.update.json! :status => 'Tweet, tweet!' Abstraction Twitter from @jnunemaker client.update('Tweet, tweet!')
  • 32. Why simply wrap?
  • 33. Insulate against change
  • 34. Leverage API documentation
  • 35. Why abstract?
  • 36. ...or writing APIs to wrap APIs
  • 37. Simplify a complex API
  • 38. Provide a business domain
  • 39. TOOLS
  • 40. Transports
  • 41. Net::HTTP
  • 42. Patron http://toland.github.com/patron/
  • 43. Typhoeus http://github.com/pauldix/typhoeus
  • 44. em-http-request http://github.com/igrigorik/em-http-request
  • 45. Parsers
  • 46. Crack http://github.com/jnunemaker/crack Puts the party in HTTParty
  • 47. JSON
  • 48. yajl-ruby http://github.com/brianmario/yajl-ruby
  • 49. multi_json http://github.com/intridea/multi_json
  • 50. Higher-level libraries
  • 51. HTTParty http://github.com/jnunemaker/httparty When you HTTParty, you must party hard!
  • 52. HTTParty - Ruby module - GET, POST, PUT, DELETE - basic_auth, base_uri, default_params, etc. - Net::HTTP for transport - Crack parses JSON and XML
  • 53. HTTParty class 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 ...
  • 54. monster_mash http://github.com/dbalatero/monster_mash HTTParty for Typhoeus, a monster. Get it?
  • 55. RestClient http://github.com/adamwiggins/rest-client
  • 56. RestClient - Simple DSL - ActiveResource support - Built-in shell RestClient.post( ! 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' } )
  • 57. Weary http://github.com/mwunsch/weary
  • 58. Weary - Simple DSL - Specify required, optional params - Async support
  • 59. Weary declare "foo" do |r| r.url = "path/to/foo" r.via = :post r.requires = [:id, :bar] r.with = [:blah] becomes r.authenticates = false r.follows = false r.headers = {'Accept' => 'text/html'} end client.foo :id => 123, :bar => 'baz'
  • 60. RackClient http://github.com/halorgium/rack-client
  • 61. RackClient - Rack API - Middleware! client = Rack::Client.new('http:// whoismyrepresentative.com')
  • 62. Faraday http://github.com/technoweenie/faraday
  • 63. Faraday - Rack-like - Middleware! - Adapters
  • 64. Faraday url = '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::Mashify end resp = conn.get do |req| req.url '/users/show.json', :screen_name => 'pengwynn' end u = resp.body u.name # => "Wynn Netherland"
  • 65. Faraday Middleware http://github.com/pengwynn/faraday-middleware
  • 66. Faraday Middleware - Hashie - Multi JSON - OAuth, OAuth2 as needed
  • 67. My current stack - Faraday - Faraday Middleware - Hashie - Multi JSON - OAuth, OAuth2 as needed
  • 68. Hashie - Mash - Dash - Trash - Clash
  • 69. HTTPScoop
  • 70. If you have an iOS app, you have an API ;-) Charles Proxy
  • 71. Testing
  • 72. Fakeweb http://github.com/chrisk/fakeweb
  • 73. VCR http://github.com/myronmarston/vcr
  • 74. Artifice http://github.com/wycats/artifice Artifice.activate_with(rack_endpoint) do # make some requests using Net::HTTP end a @wycats joint
  • 75. ShamRack http://github.com/mdub/sham_rack
  • 76. ShamRack ShamRack.at("sinatra.xyz").sinatra do get "/hello/:subject" do "Hello, #{params[:subject]}" end end open("http://sinatra.xyz/hello/ stranger").read #=> "Hello, stranger"
  • 77. ShamRack Rack 'em up! ShamRack.at("rackup.xyz").rackup do use Some::Middleware use Some::Other::Middleware run MyApp.new end
  • 78. Authentication
  • 79. Basic
  • 80. OAuth http://oauth.rubyforge.org/
  • 81. OAuth2 http://github.com/intridea/oauth2
  • 82. QUESTIONS? @pengwynn