Recent Posts

REST Fest - 3 Things I Learned

Posted on 17 Sep 2012

This post was originally published on the SmartLogic Blog.

This past weekend, I headed down to REST Fest in Greenville, South Carolina. My weekend lived up to my expectations: though I didn’t get much of a chance to work on Frenetic, I spread the word about Raddocs and RAD, and learned a lot from the API developers at the event.

For those of you who couldn’t make it, here’s a quick wrap-up of three things I learned, and, at the end of the post, the video of my 5in5 talk:

What a bad API looks like

During Mike Amundsen’s presentation he said, “Exposing your database is like showing me your underwear. I don’t wanna see that.” This was both enlightening and disheartening. My previous APIs have been mostly database table to resource. While they do their job, they definitely could be better. In the future I will definitely put more thought into the design of my APIs.

Before attending REST Fest, I didn’t know that if you create a short link relation you have to register it with a registry such as IANA or MicroFormats. The way around this is to create link relations as URIs.

An example from the Helpdesk Hackday at REST Fest:

<atom:link rel="http://helpdesk.hackday.2012.restfest.org/rels/ticket" href="http://.../tickets/9172361" type="application/vnd.org.restfest.2012.hackday+xml" />

In the same vein as registering link relations, I didn’t know you were supposed to register media types. The HTTP spec calls for them to be registered in RFC 2616. Here’s the gist: “Media-type values are registered with the Internet Assigned Number Authority (IANA [19]). The media type registration process is outlined in RFC 1590 [17]. Use of non-registered media types is discouraged.”

Linking in JSON

I learned of a new hypermedia format for JSON called Siren. I had previously seen HAL before, but I like that Siren gives you the ability to include actions in the resource. Siren is located here on GitHub.

In addition to learning about Siren, I also learned more about Collection+JSON. I had seen it before but I had only glanced at it. Collection+JSON is located here. I will definitely be giving both of these a more thorough look through for my next API project.

Overall, the weekend was jam packed with new information. Were you there? What was the most useful thing you learned? Comment here or tweet me, @ericoestrich.

And, as promised, here’s my 5in5 talk:

REST Fest 2012 \ Eric Oestrich \ FiveInFive from REST Fest on Vimeo.

REST Fest - 3 Things I'm Looking Forward To

Posted on 12 Sep 2012

This post was originally published on the SmartLogic Blog.

Rest Fest 2012

I am pretty excited about attending REST Fest this week. I am most looking forward to the following:

Getting together with other API developers

Being able to hang out with other developers who are interested in APIs is definitely the thing I’m most looking forward to. I want to absorb as much information as I can from this event.

Hacking on Frenetic

On the Thursday Hack day I want to play around with the gem Frenetic, https://github.com/dlindahl/frenetic. Right now it’s kinda awkward to use it as a client because it requires a crazy amount of chaining. I would like to be able to knock that down a lot.

api.get(api.description.links.orders.href).body.resources.orders

In addition to getting the previous command shorter, Frenetic doesn’t seem to give you easy accessors to the links that the API returns.

Talking more about Raddocs and RAD

Since I’m going to be giving a 5in5 talk when I attend REST Fest, it’s the perfect opportunity to put Raddocs and RAD in front of other developers faces. I will be giving a modified version of my “cURLin’ for Docs” presentation.

Looking forward to heading to Greenville! Tweet me @ericoestrich if you want to meet up when we’re there.

Introduction to Hypermedia APIs with Rails Presentation

Posted on 06 Sep 2012

Last week SmartLogic had an internal conference where I gave a presentation on hypermedia APIs with Rails, located here. I created an example app that’s on github. My favorite part about this talk was at the end when I attempted to change the routes the app serves up and see if my hal client still worked. It passed with flying colors.

I used the frenetic gem to create my hal client. It’s pretty verbose currently and let’s just gloss over all those periods. It’s a nice starting point for a HAL api.

require 'frenetic'

MyAPI = Frenetic.new({
  'url'          => 'http://hypermedia.dev',
  'username'     => 'qxpRbQpqAw3YugKUpErW',
  'password'     => 'qxpRbQpqAw3YugKUpErW',
  'headers' => {
    'accept' => 'application/hal+json'
  }
})

class Order < Frenetic::Resource
  api_client { MyAPI }

  def self.orders
    api.get(api.description.links.orders.href).body.resources.orders.map do |order|
      new(order)
    end
  end
end

p Order.orders

Resources

Trying out WebMachine

Posted on 05 Sep 2012

Yesterday I tried out webmachine-ruby. Overall it left a good impression on me. One thing I really liked was the separation of a single resource and a collection resource.

App = Webmachine::Application.new do |app|
  app.routes do
    add ["orders"], OrdersResource
    add ["orders", :id], OrderResource
  end
end

Any call to “/orders” will go to the OrdersResource, since you’re acting on a collection, and any call with an “id” in it will go to the single resource.

I also really liked the idea of callbacks on a resource. To point out one, in order to get a resource to respond to a certain method, you add it to the #allowed_methods:

class OrderResource
  def allowed_methods
    ["GET", "POST"]
  end

  def content_types_provided
    [["application/json", :to_json]]
  end
end

The #content_types_provided callback will call #to_json if it sees “application/json”.

One pretty big issue I faced was a lack of examples on how to use its statemachine. The example apps listed only do GET and POST requests but there wasn’t an example on how do DELETE or PUT something. Luckily I had access to someone who has used it before and could help me with the issues I came across. I’m hoping this example app can be of use to someone else looking into WebMachine.

My resulting example app is here as a gist and I’ve embedded the main app file.

require 'webmachine'
require 'webmachine/adapters/rack'
require 'json'

class Order
  attr_accessor :id, :email, :date

  DB = {}

  def self.all
    DB.values
  end

  def self.find(id)
    DB[id]
  end

  def self.next_id
    DB.keys.max.to_i + 1
  end

  def self.delete_all
    DB.clear
  end

  def to_json(options = {})
    "{\"email\":\"#{@email}\", \"date\":\"#{@date}\", \"id\":#{@id}"
  end

  def initialize(attrs = {})
    attrs.each do |attr, value|
      send("#{attr}=", value) if respond_to?(attr)
    end
  end

  def save(id = nil)
    self.id = id || self.class.next_id
    DB[self.id] = self
  end

  def destroy
    DB.delete(id)
  end
end

class JsonResource < Webmachine::Resource
  def content_types_provided
    [["application/json", :to_json]]
  end

  def content_types_accepted
    [["application/json", :from_json]]
  end

  private
  def params
    JSON.parse(request.body.to_s)
  end
end

class OrdersResource < JsonResource
  def allowed_methods
    ["GET", "POST"]
  end

  def to_json
    {
      :orders => Order.all
    }.to_json
  end

  def create_path
    @id = Order.next_id
    "/orders/#@id"
  end

  def post_is_create?
    true
  end

  private
  def from_json
    order = Order.new(params).save(@id)
  end
end

class OrderResource < JsonResource
  def allowed_methods
    ["GET", "DELETE", "PUT"]
  end

  def id
    request.path_info[:id].to_i
  end

  def delete_resource
    Order.find(id).destroy
    true
  end

  def to_json
    order = Order.find(id)
    order.to_json
  end

  private
  def from_json
    order = Order.new(params)
    order.save(id)
  end
end

App = Webmachine::Application.new do |app|
  app.routes do
    add ["orders"], OrdersResource
    add ["orders", :id], OrderResource
    add ['trace', '*'], Webmachine::Trace::TraceResource
  end
end

Jekyll Git Deployment With Bundler

Posted on 29 Aug 2012

I recently converted my blog over to Jekyll, mainly to not have MySQL running. One thing I did though was set up git deployment. I mostly followed the Jekyll guide, but I different when setting up the jekyll gem.

The starting post-receive from Jekyll Deployment Guide.

hooks/post-receive (original)
GIT_REPO=$HOME/myrepo.git
TMP_GIT_CLONE=$HOME/tmp/myrepo
PUBLIC_WWW=/var/www/myrepo

git clone $GIT_REPO $TMP_GIT_CLONE
jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE
exit

I did bundler install --deployment so that it would be in the local directory. The problem with this is that jekyll then picks up the test posts in the gem as your posts. Now I had a ton of bad posts on my blog. (You may have noticed them in the feed.)

I also set it up so that it doesn’t blow away the repo (and the gems) every time I push up a new post.

hooks/post-receive (final)
GIT_REPO=$HOME/repos/blog.oestrich.org
TMP_GIT_CLONE=$HOME/tmp/blog.oestrich.org
PUBLIC_WWW=$HOME/vhosts/blog.oestrich.org

unset GIT_DIR

if [ -d $TMP_GIT_CLONE ]; then
  cd $TMP_GIT_CLONE

  git pull origin master
else
  git clone $GIT_REPO $TMP_GIT_CLONE

  cd $TMP_GIT_CLONE
fi

bundle install --deployment

# Remove the sample jekyll site from the test suite
rm -rf $TMP_GIT_CLONE/vendor/bundle/ruby/1.9.1/gems/jekyll-0.11.2/test/source

bundle exec jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW

exit
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.