Making and Breaking Web Services (with Ruby) Chris Wanstrath Err Free http://errfree.com
May 13, 2015
Making and Breaking Web Services(with Ruby)
Chris WanstrathErr Free
http://errfree.com
http://farm1.static.flickr.com/138/320699460_b8e7c1e7e6_o.jpg
SOAP
• Simple Object Access Protocol?
• Lies.
• Service Oriented Architecture Protocol
• wtf.
Newsletters!
“Outbound”
• Slow response time
• Duplication of data
• Hard to debug
• require ‘soap/wsdlDriver’
Ruby SOAP Library: Your Friend
• Creates methods on the fly
• Seems to work pretty well
• Transparently converts Ruby types to SOAP definitions
Ruby SOAP Library: Your Enemy
• Hard to debug (dump req/res to file)
• No one has ever used it
• There are not any alternatives
• The code is a jungle
Why use SOAP?
• One reason: legacy.
Wrapping SOAP
def update_user(email, subs = [], unsubs = []) client.updateUser(brand, email, email, demo, subs, unsubs)end
Wrapping SOAP
def update_user(email, subs = [], unsubs = []) client.updateUser(brand, email, email, demo, subs, unsubs)end
def get_user(email) client.getUser(email, brand)end
Wrapping SOAP
def update_user(email, subs = [], unsubs = []) client.updateUser(brand, email, email, demo, subs, unsubs)end
def get_user(email) client.getUser(email, brand)end
Wrapping SOAP
def update_user(email, subs = [], unsubs = []) client.updateUser(brand, email, email, demo, subs, unsubs)end
def get_user(email) client.getUser(email, brand)end
Testing SOAP
• Use mocks
• Mocha: http://mocha.rubyforge.org
Testing SOAP
def test_get_user_should_hit_client email = '[email protected]' Outbound.client.expects(:getUser).with(email, Outbound.brand) Outbound.get_user(email)end
Testing SOAP
soap_methods = { :getUser => true, :updateUser => true}
Outbound.stubs(:client).returns(mock('SOAP Service', soap_methods))
Running a SOAP Server in Ruby
Just Kidding
Microformats!• Your website is your API
• Plant classes in HTML
• Tell parsers what information is important
• http://microformats.org
hReview
hReview<div id="review_16873" class="hreview"> <h5 class="item"><span class="fn">Beringer California Collection White Merlot 2005 </span></h5> <abbr class="dtreviewed" title="20070420">(1 day ago)</abbr> <span class="reviewer vcard"> <img class="photo" src="/assets/avatars/c19d1b2080f73765d420b461d3133ffa.jpg" height="48" width="48" alt="buddy icon" /> <a class="url fn" href="/people/garyvaynerchuk">garyvaynerchuk</a> </span> <abbr class="rating" title="50.0">50.0<em>/100</em></abbr> <blockquote class="description">Had this in an industry event the other day, man o man this was sugar water less the water;)</blockquote> <p class="tags">Tasting Tags: <a href="/tags/pink" rel="tag" class="rel-tag" title="view all wines with this tag">pink</a> <a href="/tags/sugar" rel="tag" class="rel-tag" title="view all wines with this tag">sugar</a></p></div>
hReview<div id="review_16873" class="hreview"> <h5 class="item"><span class="fn">Beringer California Collection White Merlot 2005 </span></h5> <abbr class="dtreviewed" title="20070420">(1 day ago)</abbr> <span class="reviewer vcard"> <img class="photo" src="/assets/avatars/c19d1b2080f73765d420b461d3133ffa.jpg" height="48" width="48" alt="buddy icon" /> <a class="url fn" href="/people/garyvaynerchuk">garyvaynerchuk</a> </span> <abbr class="rating" title="50.0">50.0<em>/100</em></abbr> <blockquote class="description">Had this in an industry event the other day, man o man this was sugar water less the water;)</blockquote> <p class="tags">Tasting Tags: <a href="/tags/pink" rel="tag" class="rel-tag" title="view all wines with this tag">pink</a> <a href="/tags/sugar" rel="tag" class="rel-tag" title="view all wines with this tag">sugar</a></p></div>
mofo$ sudo gem install mofoSuccessfully installed mofo-0.2.2$ irb -rubygems>> require 'mofo/hreview'=> true>> review = HReview.find :first => 'http://corkd.com/wine/view/21670' => #<HReview:0x1598d04 ...>>> review.properties=> ["description", "item", "dtreviewed", "tags", "rating", "reviewer"]>> review.rating=> 50.0>> review.item.fn=> "Beringer California Collection White Merlot 2005">> review.reviewer.fn=> "garyvaynerchuk"
mofo/hreview.rbclass HReview < Microformat one :version, :summary, :type, :dtreviewed,
:rating, :description
one :reviewer => HCard
one :item! do one :fn endend
microformat.rb
def collector collector = Hash.new([]) def collector.method_missing(method, *classes) super unless %w(one many).include? method.to_s self[method] += Microformat.send(:break_out_hashes, classes) end collectorend
mofo supports...
• hCard
• hCalendar
• hReview
• hEntry
• hResume
• xoxo
• geo
• adr
• xfn
What else can they do?
Operator
Operator
Okay.
Hpricot
( by _why )
Hpricot$ irb -rubygems -r'open-uri'>> require 'hpricot'=> true>> page = Hpricot open('http://google.com')=> #<Hpricot::Doc ...>>> page.search(:a).size=> 20>> page.at(:a)=> {elem <a href="/url?sa=p&pref=ig&pval=3
&q=http://www.google.com/ig%3Fhl%3Den&usg=AFrqEzfPu3dYlSVsfjI7gUHePgEkcx_VXg"> "Personalize this page" </a>}
Hpricot
Can use XPATH, CSS selectors, whatever, to search
Hpricot
>> page = Hpricot(open('http://brainspl.at'))=> #<Hpricot::Doc ...>>> page.search('.post').size=> 10
Hpricot
>> corkd = 'http://corkd.com/wine/view/21670'=> 'http://corkd.com/wine/view/21670'>> page = Hpricot(open(corkd))=> #<Hpricot::Doc ...>>> page.search('.hreview').size=> 4
Hpricot/:mofo>> page.at('.hreview').at('.item').at('.fn').inner_text=> "Beringer California Collection White Merlot 2005"
>> review.item.fn=> "Beringer California Collection White Merlot 2005"
Oh, you can use Hpricot for XML, too.
<Export> <Product> <SKU>403276</SKU> <ItemName>Trivet</ItemName> <CollectionNo>0</CollectionNo> <Pages>0</Pages> </Product></Export>
Oh, you can use Hpricot for XML, too.
fields = %w(SKU ItemName CollectionNo Pages)
doc = Hpricot(open("my.xml"))(doc/:product).each do |xml_product| attributes = fields.inject({}) do |hash, field| hash.merge(field => xml_product.at(field).innerHTML) end Product.create(attributes)end
( also there’s Hpricot::XML() )
But who uses XML?
Cheat!http://cheat.errtheblog.com
(insert short, live demo here)
Thanks
• http://mofo.rubyforge.org
• http://code.whytheluckystiff.net/hpricot
• https://addons.mozilla.org/en-US/firefox/addon/4106
• http://microformats.org
• http://upcoming.yahoo.com/
• http://corkd.com/
• http://chow.com
• http://chowhound.com
Thanks
• http://ronrothman.com/gallery/cnet/cnet_neon
• http://flickr.com/photos/bootbearwdc/466751240/
• http://flickr.com/photos/segana/320699460/
• http://flickr.com/photos/spiffariffic/456211526/