Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JSON and the APInauts

JSON and the APInauts

7e19cd5486b5d6dc1ef90e671ba52ae0?s=128

Wynn Netherland

September 17, 2011
Tweet

Transcript

  1. JSON AND THE ARGONAUTS API WYNNNETHERLAND

  2. whoami

  3. +

  4. None
  5. I write API wrappers A lot of API wrappers!

  6. & more!

  7. Why create API wrappers?

  8. After all, we have

  9. curl

  10. curl http://api.twitter.com/1/users/show.json?screen_name=pengwynn

  11. Net::HTTP

  12. url = "http://api.twitter.com/1/users/show.json?screen_name=pengwynn" Net::HTTP.get(URI.parse(url))

  13. Because we're Rubyists, and we want

  14. Idiomatic access

  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. {"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, ... }}
  17. Rubyified keys

  18. {"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, ... }}
  19. {"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, ... }}
  20. ... and method names

  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. # 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. # 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 More Ruby like than
  23. SYNTACTIC SUGAR

  24. Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch()

  25. Twitter::Search.new.from('jnunemaker').to('pengwynn').hashed('ruby').fetch() Method chaining

  26. stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores

  27. stores = client.stores({:area => ['76227', 50]}).products({:salePrice => {'$gt' => 3000}}).fetch.stores

    Method chaining
  28. client.statuses.update.json! :status => 'this status is from grackle'

  29. client.statuses.update.json! :status => 'this status is from grackle' Method chaining

    Bang for POST
  30. APPROACHES

  31. Simple Wrapping

  32. SOME TWITTER EXAMPLES Twitter Auth from @mbleigh user.twitter.post( '/statuses/update.json', 'status'

    => 'Tweet, tweet!' ) Grackle from @hayesdavis client.statuses.update.json! :status => 'Tweet, tweet!' Twitter from @jnunemaker client.update('Tweet, tweet!') Wrapping Wrapping... with style Abstraction
  33. Why simply wrap?

  34. Insulate against change

  35. Leverage API documentation

  36. Why abstract?

  37. ...or writing APIs to wrap APIs

  38. Simplify a complex API

  39. Provide a business domain

  40. TOOLS

  41. Transports

  42. Net::HTTP

  43. Patron http://toland.github.com/patron/

  44. Typhoeus http://github.com/pauldix/typhoeus

  45. em-http-request http://github.com/igrigorik/em-http-request

  46. Parsers

  47. Crack Puts the party in HTTParty http://github.com/jnunemaker/crack

  48. JSON

  49. yajl-ruby http://github.com/brianmario/yajl-ruby

  50. multi_json http://github.com/intridea/multi_json

  51. Higher-level libraries

  52. HTTParty When you HTTParty, you must party hard! http://github.com/jnunemaker/httparty

  53. HTTParty - Ruby module - GET, POST, PUT, DELETE -

    basic_auth, base_uri, default_params, etc. - Net::HTTP for transport - Crack parses JSON and XML
  54. 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 ...
  55. monster_mash http://github.com/dbalatero/monster_mash HTTParty for Typhoeus, a monster. Get it?

  56. RestClient http://github.com/adamwiggins/rest-client

  57. RestClient - Simple DSL - ActiveResource support - Built-in shell

    RestClient.post( ! 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' } )
  58. Weary http://github.com/mwunsch/weary

  59. Weary - Simple DSL - Specify required, optional params -

    Async support
  60. Weary declare "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
  61. RackClient http://github.com/halorgium/rack-client

  62. RackClient - Rack API - Middleware! client = Rack::Client.new('http:// whoismyrepresentative.com')

  63. Faraday http://github.com/technoweenie/faraday

  64. Faraday - Rack-like - Middleware! - Adapters

  65. 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"
  66. Faraday Middleware http://github.com/pengwynn/faraday-middleware

  67. Faraday Middleware - Hashie - Multi JSON - OAuth, OAuth2

    as needed
  68. My current stack - Faraday - Faraday Middleware - Hashie

    - Multi JSON - OAuth, OAuth2 as needed
  69. Hashie - Mash - Dash - Trash - Clash

  70. None
  71. HTTPScoop

  72. Charles Proxy If you have an iOS app, you have

    an API ;-)
  73. Testing

  74. Fakeweb http://github.com/chrisk/fakeweb

  75. VCR http://github.com/myronmarston/vcr

  76. Artifice Artifice.activate_with(rack_endpoint) do # make some requests using Net::HTTP end

    a @wycats joint http://github.com/wycats/artifice
  77. ShamRack http://github.com/mdub/sham_rack

  78. 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"
  79. ShamRack ShamRack.at("rackup.xyz").rackup do use Some::Middleware use Some::Other::Middleware run MyApp.new end

    Rack 'em up!
  80. Authentication

  81. Basic

  82. OAuth http://oauth.rubyforge.org/

  83. OAuth2 http://github.com/intridea/oauth2

  84. QUESTIONS? @pengwynn