A Ruby gem for the bol.com developer API

02-02-2012
Tagged ruby, rubygems, bol.com
TLDR: I released a Ruby gem for the Bol.com API

It has bugged me for a long time that I could not access product information from bol.com the same way I could from Amazon.com. When bol.com released their public API some time ago, I still couldn’t. Not easily. So I wrote a Ruby library for the Bol.com API.

The bol.com API allows you to fetch detailed information for common products, such as books, DVDs and toys, search for products by keyword, or list bestsellers. The API is not too complex: it’s just a handful of endpoints, a couple of available query parameters and a request signature.

I built a wrapper around this API that exposes the available operations and handles the difficult parts of request signing and XML parsing. All you, as the developer, have to do is provide the access credentials. All operations give you nice, clean Ruby objects back, such as a Bol::Product.

Getting started

You need to sign up for a developer account first. When your account has been approved, you can request an API key. The key has two parts – one public, one secret – that will be used by bol.com to make sure you really are who you say you are when you make a request.

Once you have both your access key and its secret, you can get started by installing the Ruby gem:

$ gem install bol

An example application

Let’s create a very simple Sinatra application to search the bol.com store (see the completed app in one file). Create an application file app.rb:

require 'sinatra'

get '/' do
  erb :search
end

Add a simple form view:

<form method="post" action="/search">
  <label>Query: <input type="text" name="q"></label>
  <input type="submit">
</form>

Run the app to confirm everything works:

$ ruby -rubygems app.rb

When you browse to http://localhost:2567 you can see the search page, but it doesn’t do anything yet. Let’s add a search action:

post '/search' do
  @products = []
  erb :results
end

And a view to display results:

<ol>
<% @products.each do |product| %>
  <li><%= product.title %></li>
<% end %>
</ol>

Implementing search

We’ve added a /search route that will somehow set an array of products, and then render them to an ordered list on the page. Simple enough. Now to actually search some products:

post '/search' do
  @products = Bol.search params[:q]      
  erb :results
end

Searching the bol.com website is as easy as Bol.search(params[:q]). Restart the app, and try it out. You will get an error, complaining that the gem is not properly configured. We need to provide our access key and its secret, so they can be used to sign our requests:

Bol.configure do |c|
  c.access_key = '123256789'
  c.secret     = 'abcdefghi'
end

When you restart the application, you should be able to search bol.com by keyword and get a list of titles back.

Showing product details

Let’s go one step further and add some product details. We’ll create a new route for that:

get '/product/:id' do
  @product = Bol::Product.find params[:id]
  erb :product
end

We can use Product#find to find a particular product on bol.com by its internal ID. We’ll create a link to the detail page in our search results:

<ol>
<% @products.each do |product| %>
  <li>
    <a href="/product/<%= product.id %>">
      <%= product.title %>
    </a>
  </li>
<% end %>
</ol>

We also need a view for our new action:

<h1><%= @product.title %></h1>
<dl>
  <% @product.attributes.each_pair do |k, v| %>
  <dt><%= k %></dt>
  <dd><pre><%= v %></pre></dd>
  <% end %>
</dl>

Restart the app, perform a search and click on a result. You should see all available product details. Note that there are several sizes of cover image available, and that the author attribute is an Array – there can be more than one, after all.

Scoping search results to categories

Now we want to limit our search results to a particular category of products. Bol.com products are extensively categorized and we can look up those categories and search in them. Let’s add a drop-down list of categories to search to our search form:

get '/' do
  @categories = Bol.categories
  erb :search
end

post '/search' do
  @products = Bol::Scope.new(params[:category_id])
    .search params[:q]      
  erb :results
end

And in the view:

<form method="post" action="/search">
  <select name="category_id">
    <% @categories.each do |category| %>
    <option value="<%= category.id %>">
      <%= category.name %> (<%= category.count %>)
    </option>
    <% end %>
  </select>
  <input type="text" name="q">
  <input type="submit">
</form>

Once we’ve reloaded the application, we can choose a category to search in and get results limited to that category. Categories are nested, so you can get subcategories using Bol::Scope.new(some_id).categories. And there are also refinements, such as groupings by price or brand and other attributes, but they work similarly to categories.

Referral links

Then only referral links remain. It is a good idea to link to products on bol.com, so you can get a kickback on any sales resulting from the traffic you send over. This is not strictly a feature of the developer API, but it is so commonly used, I just threw it in here. You can simply ask a product for its referral URL, given a specific referral ID:

product = Bol.find(params[:id])
product.referral_link('my-site-id')
# => "http://..."

Other features

This example application showcases the basics of the bol gem, but it includes some more:

  • Ordering and limiting of number of results
  • Automatic pagination
  • Joining and subtracting categories and refinements to create complex scopes
  • List popular or bestselling products

See the project README file for more information.

Example application and source code

That’s all you need to know to get started. You can see the entire example application in this gist. You can find the source for this Ruby gem on Github, where I also keep the API documentation and track issues. The gem is still in beta stage, so it can be field-tested before getting an actual stamp-of-approval by releasing a version 1.0. Try it out and do let me know if you make anything awesome with it!