Searching for Books on Amazon

Problem

You want to incorporate information about books or other cultural artifacts into your application.

Solution

Amazon.com exposes a web service that gives you access to all kinds of information on books, music, and other media. The third-party Ruby/ Amazon library provides a simple Ruby interface to the Amazon web service.

Heres a simple bit of code that searches for books with Ruby/Amazon, printing their new and used prices.

	require amazon/search

	$AWS_KEY = Your AWS key goes here # See below.

	def price_books(keyword)
	 req = Amazon::Search::Request.new($AWS_KEY)
	 req.keyword_search(keyword, ooks, Amazon::Search::LIGHT) do |product|

	 newp = product.our_price || Not available
	 usedp = product.used_price || 
ot available
	 puts "#{product.product_name}: #{newp} new, #{usedp} used."
	 end
	end

	price_books(
uby cookbook)
	# Ruby Cookbook (Cookbooks (OReilly)): $31.49 new, not available used.
	# Rails Cookbook (Cookbooks (OReilly)): $25.19 new, not available used.
	# Ruby Anns Down Home Trailer Park Cookbook: $10.85 new, $3.54 used.
	# Rubys Low-Fat Soul-Food Cookbook: Not available new, $12.43 used.
	# …

To save bandwidth, this code asks Amazon for a "light" set of search results. The results won include things like customer reviews.

Discussion

Whats going on here? In one sense, it doesn matter. Ruby/Amazon gives us a Ruby method that somehow knows about books and their Amazon prices. Its getting its information from a database somewhere, and all we need to know is how to query that database.

In another sense, it matters a lot, because this is just one example of a REST-style web service. By looking under the cover of the Amazon web services, you can see how to use other REST-style services like the ones provided by Yahoo! and Flickr.

REST-style web services operate directly on top of HTTP. Each URL in a REST system designates a resource or a set of them. When you call keyword_search, Ruby/ Amazon retrieves a URL that looks something like this:

	http://xml.amazon.com/onca/xml3?KeywordSearch=ruby+cookbook&mode=books…

This URL designates a set of Amazon book records that match the keywords "ruby cookbook". Ruby/Amazon uses the Net::HTTP library to send a GET request to this URL. Amazon returns a representation of the resource, an XML document that looks something like this:

	
	11
	 2
	 
	 
Ruby Cookbook Book <Authors> <Author>Lucas Carlson <Author>Leonard Richardson September, 2006 OReilly Media

Ruby/Amazon uses REXML to parse this XML data and turn it into Amazon::Product objects. An Amazon::Product is a lot like a Ruby Struct: its got a bunch of member methods for getting information about the object (you can list these methods by calling Product#properties). All that information is derived from the original XML.

A REST web service works like a web site designed for a software program instead of a human. The web is good for publishing and modifying documents, so REST clients make HTTP GET requests to retrieve data, and POST requests to modify server state, just like youd do from a web browser with an HTML form. XML is good for describing documents, so REST servers usually give out XML documents that are easy to read and parse.

How does REST relate to other kinds of web services? REST is a distinct design philosophy, but not all "REST-style" web services take it as gospel.[2] Theres a sense in which "REST" is a drive for simpler web services, a reaction to the complexity of SOAP and the WS-[3] standards. Theres no reason why you can use SOAP in accordance with the REST philosophy, but in practice that never seems to happen.

[2] Amazons web services are a case in point. They use GET requests exclusively, even when they e modifying data like the items in a shopping cart. This is very unRESTful because "put the Ruby Cookbook in my shopping cart" is a command, not an object the way a set of books is an object. To avoid the wrath of the pedant I refer to Amazon Web Services as a "REST-style" service. It would be more RESTful to define a separate resource (URL) for the shopping cart, and allow the client to POST a message to that resource saying "Hey, shopping cart, add the Ruby Cookbook to yourself."

[3] Amazons web services are a case in point. They use GET requests exclusively, even when they e modifying data like the items in a shopping cart. This is very unRESTful because "put the Ruby Cookbook in my shopping cart" is a command, not an object the way a set of books is an object. To avoid the wrath of the pedant I refer to Amazon Web Services as a "REST-style" service. It would be more RESTful to define a separate resource (URL) for the shopping cart, and allow the client to POST a message to that resource saying "Hey, shopping cart, add the Ruby Cookbook to yourself."

Like REST, XML-RPC and SOAP web services run atop HTTP.[4] But while REST services expect clients to operate on a large URL space, XML-RPC and SOAP services are generally bound to a single "server" URL. If you have a "resource" to specify, you include it in the document you send to the server. REST, XML-RPC, and SOAP all serve XML documents, but XML-RPC and SOAP serve serialized versions of data structures, and REST usually serves RDF, Atom, or Plain Old XML.

[4] SOAP services can run over other protocols, like email. But almost everyone uses HTTP. After all, they e "web services," not "Internet services."

If there were no Ruby/Amazon library, it wouldn be hard to do the work yourself with Net::HTTP and REXML. Itd be more difficult to write a Ruby XML-RPC client without xmlrpc4r, and much more difficult to write a SOAP client without SOAP::RPC::Driver.

The downside of this flexibility is that, at least for now, every REST service is different. Everyone arranges their resources differently, and everyones response documents need to be parsed with different code. Ruby/Amazon won help you at all if you want to use some other REST service: youll need to find a separate library for that service, or write your own using Net::HTTP and REXML.

See Also

  • Like Googles web services and others, Amazons can only be used if you sign up for an identifying key. You can sign up for an AWS key at the Amazon Web Services site (http://www.amazon.com/gp/browse.html?node=3435361)
  • Get Ruby/Amazon at http://www.caliban.org/ruby/ruby-amazon.shtml: you can download it as a tarball and run setup.rb to install it; the same site hosts generated RDoc for the library; see especially http://www.caliban.org/ruby/ruby-amazon/classes/Amazon.html
  • The Amazon Web Services documentation (http://www.amazon.com/gp/browse.html/103-8028883-0351026?node=3435361)
  • Recipe 11.2, "Extracting Data from a Documents Tree Structure"
  • Recipe 14.1, "Grabbing the Contents of a Web Page"
  • Recipe 16.2, "Finding Photos on Flickr"
  • Recipe 16.4, "Writing a SOAP Client"


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net