The Hand-Fed API

Posted by Chad

While planning any application, there is one constant: I may open things up with an API in the future. Maybe I won’t go production without it, or maybe I put the API on the back burner for a future release. Either way, I try to keep that in mind while building the HTML controllers/views. Nothing new there, I’m sure everyone does this these days, but it helped me stumble upon a API method that I think would be pretty cool.

I, as the API provider, want to give the easiest use to all developers using my service. Naturally, that means encouraging the use of Ruby on Rails. Not entirely, it will be just as easy for non-RoR users to develop with the API but we can do so much more for those on Rails. For example, give them a model with the migration, tests, etc.

So here’s the plan, let’s start by looking at some code examples of how our API should be designed to help out a RoR developer.

Inside a rails app do script/generate scaffold_resource bid end.

Migration
create_table :bids do |t|
    t.column :amount, :decimal, :precision => 9, :scale=>4
    t.column :creation_date, :datetime
    t.column :key, :string
    t.column :last_modified_date, :datetime
    t.column :listing_key, :string
    t.column :member_key, :string
    t.column :minimum_rate, :decimal, :precision => 6, :scale=>5
    t.column :participation_amount, :decimal, :precision => 9, :scale=>4
    t.column :status, :integer
    # Your own stuff
end
Once the developer has this in place, then they just follow some simple logic.
# Make a Bid instance
xml = Net::HTTP.get('api-host.cm', '/bids/1.xml')
hash = Hash.from_xml( xml )
@bid = Bid.new hash['bid']

# Developer saves it
@bid.save

# Developer uses it
puts "Winning" if @bid.status == 2
Easy, right? Let’s make it a one liner out of respect for all you Rubyist ninjas… or pirates? I won’t judge.
@bid = Bid.new( Hash.from_xml( Net::HTTP.get('api-host.cm', '/bids/1.xml') )['bid'] )

Fun stuff. Back to my prospective as an API provider. Wow. I did virtually nothing and people can tap into my API literally within 20 seconds of turning on their computer. That’s right, I timed myself to get that statistic and it assumes you have rails installed and ready to go.

The API’s XML file remains easy for any developer to use. It’s important to note that all of this works because the API service runs render :xml => @bid.to_xml such as with the generated REST scaffolding controllers. Rendering the exact XML format that will be recognized by the developers app. If you are not running Rails on your API service, provide an endpoint with the XML formated for RoRs developers. I don’t see this being done anytime soon, but you never know with the growth of RoR thus far.

Thought: For all I know this is what Action Web Services is all about. I’ve never read up on it so I don’t know anything about it. Not really investigating it either shrug.

One Dollar Give Away! To the first person who correctly guess what API was used in the above examples. Just leave your guess as a comment and I’ll send you a buck via Paypal.

Putting JavaScript Inline

Posted by Chad

Sometimes, usually in development, I find it useful to have my Javascripts printed inline rather than using the <script src="/path/to"> tags that are generated by javascript_include_tag.

With javascript_inline_tag you can simply declare your Javascripts just like you would with javascript_include_tag and it will spit out the script into your view/layout.

Put it where you like, but I chose to keep with my application_helper.rb.

javascript_inline_tag
module ApplicationHelper
  # ..... your app helpers, per usual
end

module ActionView::Helpers::AssetTagHelper
  def javascript_inline_tag(*sources)
    if sources.include?(:defaults) 
      sources = sources[0..(sources.index(:defaults))] + 
      @@javascript_default_sources.dup + 
      sources[(sources.index(:defaults) + 1)..sources.length]
      sources.delete(:defaults) 
      sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js") 
    end

    sources.collect do |source|
      source = javascript_path(source).sub(/\?\d+/,'')
      contents = ''
      File.open("#{RAILS_ROOT}/public#{source}").each do |line|
        contents << line
      end
      javascript_tag(contents)
    end.join("\n")
  end
end
Sample Usage
<%= javascript_inline_tag :defaults,'niftycube' %>
Notes
  1. You can not pass an options hash.
  2. For production, I’ll just say, consider caching (browser&server) and page size.
  3. Nifty Corners Cube is an awesome script that I recently discovered.
  4. You may find render :file => '' to work for you, I just thought it wasn’t flexible enough for this situation.