Recent Posts

Creating a Hypermedia Client

Posted on 06 Dec 2012

Over the past few weeks I wrote a client for a hypermedia api that I created. I think I ended up coming across a pattern that I like in regards to how it’s structured.

I have three basic object types: services, loaders, and resources.

The http client used is the gem Farday.

Services

A service is an object that performs an action. For example I have one service that registers users.

class UserRegistrationService < Struct.new(:email, :password)
  def perform
    client.post(user_registration_url, {
      :user => {
        :email => email,
        :password => password
      }
    }
  end
end

Resources

A resource is a data only object. For example I might have a resource for an order.

class Order
  def self.load(json_string)
    new(JSON.parse(json_string))
  end

  def initialize(attrs)
    @email = attrs.fetch("email")
    @links = Links.new(attrs.fetch("_links"))
  end
end

Loaders

A loader is an object that loads up resources for me, going through any of the hypermedia bits that might be necessary. For example I might have a loader that gets a list of orders.

class OrdersLoader < Struct.new(:user)
  def load
    client.basic_auth(user.email, user.password)

    response = client.get("/")
    root = Root.load(response.body)

    response = client.get(root.links.fetch("orders"))
    Orders.load(response.body)
  end
end

In the end I was pretty happy with how this structure ended up and was able to fairly quickly come up with an app that used it.

RubyConf 2012 Links to Follow Up On

Posted on 28 Nov 2012

This post was originally published on the SmartLogic Blog.

RubyConf 2012....so many Links!

At RubyConf, there’s so much more to dig into after every session. From apps, to people, to blog posts, I started to keep tracks of links I’d like to follow up on after the conference. I thought I’d share them here, for everyone’s reference. I’m updating from the conference, as quickly as I can manage.

Please feel free to comment if you’d like to add a link to the list.

From Day 1:

  1. Rubinius : Use Ruby
  2. odrk-http-client/perf/bm.rb at master - asakusarb/odrk-http-client
  3. Ruby HTTP clients features 2012nahi/httpclient
  4. MagLev
  5. Refinements in Ruby - Timeless
  6. Librato Metrics
  7. Home | Metrics
  8. Operational Intelligence, Log Management, Application Management, Enterprise Security and Compliance | Splunk
  9. amatsuda/rspec-refinements - GitHub
  10. eric/metriks
  11. Code Climate. Hosted static analysis for Ruby source code.
  12. RubySpec: The Standard You Trust
  13. Jesse Storimer

 

From Day 2:

  1. The Pragmatic Bookshelf | The dRuby Book
  2. tenderlove/tusk
  3. Improve your Code Quality at RubyConf 2012
  4. Celluloid: Actor-based Concurrent Objects for Ruby
  5. Ruby, Rails, DCI and OOP. Don’t just make abstractions, write clean, intention-revealing Ruby. Clean Ruby by Jim Gay teaches about OOP, DCI, and more!
  6. Ruby Under a Microscope - Pat Shaughnessy
  7. Unlimited Novelty
  8. 37signals/sub
  9. tdiary (tDiary)
  10. T by sferik
  11. Schneems - UT on Rails
  12. Resque Triage
  13. josephwilk/creative-machine
  14. burtlo/metro

 

From Day 3:

  1. Videos - WindyCityRails
  2. Gosu, 2D game development library
  3. Sikuli Script - Home
  4. tenderlove/racc

 

Reach out on Twitter @ericoestrich if you’d like to catch up at RubyConf, or ask a question about any of these links.

Using let in Controllers

Posted on 21 Nov 2012

let in rspec is one of my favorite features. The decent_exposure is similar to let, but it ends up doing way more for you than I want it to. I have been doing mostly API work in Rails recently so it doesn’t fit.

To fix this I ended up writing my own simple version of let to use in my controllers.

lib/let.rb
def self.let(method, &block)
  define_method(method) do
    @lets ||= {}
    @lets[method] ||= instance_eval(&block)
  end
end

Since I ended up pasting this code in most of the projects I’m in, I ended up writing a gem letter. It’s simple to use.

app/controllers/application_controller.rb
class ApplicationController
  extend Letter

  let(:current_user) { User.find(session[:user_id]) }
end

Currently this gem doesn’t work if you have views. So a simple addition to make it work with views would be:

app/controllers/application_controller.rb
class ApplicationController
  extend Letter

  def self.let(method, *args)
    super
    helper_method(method)
  end

  let(:current_user) { User.find(session[:user_id]) }
end

ActiveSupport::Notifications for Metrics

Posted on 14 Nov 2012

The other week I had to speed up an end point of an API I’m working on, and since I wanted to do it right I used metrics. A coworker pointed me on to ActiveSupport::Notification.instrument previously so I gave it a go here.

I ended up creating a module that you can include into a class which will instrument every method. I don’t think it’s the nicest code ever but it was handy in getting a somewhat large class set up quickly.

It’s available in this gist, but I’ve also included it below.

lib/notifications.rb
module Notifications
  extend ActiveSupport::Concern

  module ClassMethods
    def method_added(method_name)
      @methods ||= []
      return if @methods.include?(method_name) || method_name =~ /_old$/
      @methods << method_name

      class_eval %{alias #{method_name}_old #{method_name}}

      define_method(method_name) do |*args|
        instrument_name = "#{method_name}.#{self.class.name.underscore}"
        ActiveSupport::Notifications.instrument(instrument_name) do
          send("#{method_name}_old", *args)
        end
      end
    end
  end
end

You also need to set up something that will log the instruments so you can see them.

config/initializers/notifications.rb
ActiveSupport::Notifications.subscribe(/my_class$/) do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  Rails.logger.warn "%7.2fms %s" % [event.duration, event.name]
end

Resources

  1. ActiveSupport::Notifications

Turning Controller Actions into Services

Posted on 09 Nov 2012

This post was originally published on the SmartLogic Blog.

SRP keeps your code from behaving like this.

When you’re developing an API, controller actions have a tendency to get large and inefficient. You can keep chopping controller actions into smaller pieces, but turning them into services may be where you want to go. The main reason for this is because you can get validation of the data before you use it to perform the service, making code more reliable.

What is a service and when would you need to make one?

A service is a class that interacts with multiple models. If a method on a model is going to access more than itself and maybe one neighbor then it should be pulled out into a service. Single Responsibility Principle (SRP) essentially states that a class should do just one thing. With this, we’re making our class do just one thing: create an order. That way, we don’t have a “fat model” that violates SRP.

Here’s an example app on github to supplement the code below.

app/controllers/orders_controller.rb
class OrdersController < ApplicationController
  def create
    service = OrderCreationService.new(current_user, params[:order])
    service.perform

    if service.successful?
      respond_with service.order
    else
      respond_with service.errors, :status => 422
    end
  end
end
app/services/order_creation_service.rb
class OrderCreationService
  include ActiveModel::Validations

  validates :name, :presence => true

  attr_reader :user, :params, :order, :name

  delegate :as_json, :to => :order

  def initialize(user, params)
    @user = user
    @params = params

    params.each do |param, value|
      instance_variable_set("@#{param}", value) if respond_to?(param)
    end
  end

  def perform
    return unless valid?

    # This can be done with only one line, or you can go nuts and make
    # this much more expansive if your desired functionality demands it
    @order = user.orders.create(params)
  end

  def successful?
    valid? && order.persisted?
  end
end

Here’s how this gives you the nice ability of having validations around the parameters your API takes:

$ curl -X POST http://localhost:3000/orders
{ 'errors': { 'name': ["can't be blank"] } }

With this method, your API development results in cleaner, more reliable code that will be easier for both internal developers and external developers to work with. Also, be sure to test via RspecApiDocumentation and Raddocs.

For more like this, follow SmartLogic on LinkedIn or like us on Facebook.
Image Source

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.