Tuesday, 23 December 2014

12 Tips of Christmas - 12 Testing your API

12 Tips of Christmas - 12 Testing your API

In our final tip, we're going to take a look at testing our API, which now looks like this

module API
  module V1
    class Posts < Grape::API
      version 'v1'
      format :json

      resource :posts do
        desc "Return 10 most recent posts"

        get do
          posts = Post.most_recent.limit(10)
          present :posts, posts, with: API::V1::Entities::Post
        end

        desc 'Find a specific post'
        params do
          requires :id, type: Integer, desc: "The ID of the post"
        end
        get ':id' do
          post = Post.find(params[:id)
          present :post, post, with: API::V1::Entities::Post              
        end
      end

    end
  end
end

To begin, we want to ensure that our API returns the data we expect it to

# spec/api/v1/post_spec.rb

describe API::V1::posts do
  describe "GET /api/v1/posts" do
    it "returns an empty array of statuses" do
      get "/api/v1/posts"
      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[]})
    end

    it "filters based on names" do
      expected_post = create(:post, content: "Foobar")
      unexpected_post = create(:post, content: "Baz")
      get "/api/v1/posts?content=Foobar"

      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[{"id"=>expected_post.id,
                                                           "content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"
                                                           }]})
    end
    it "filters based on location id" do
      expected_post = create(:post, content: "Foobar")
      unexpected_post = create(:post, content: "Baz")
      get "/api/v1/posts?place_id=Quas"

      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[{"id"=>expected_post.id,
                                                           "content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"
                                                          }]})
    end
  end
end

As you can see these function very similar to a request spec and are implemented accordingly. The utilisation of the JSON.parse ensures our content that is exposed matched what we expect.

A simpler version for this is using airborne a Gem designed to not only verify the type of content we return, but the content itself, for example:

it 'should validate types' do
  expected_post = create(:post, content: "Foobar")
  unexpected_post = create(:post, content: "Baz")
  get "/api/v1/posts?content=Foobar"
  expect_json({"posts"=>[{"id"=>expected_post.id,"content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"}]})
  expect_json_types({id: :integer)
end

So now you have no excuse for not testing your API!

Sunday, 21 December 2014

12 Tips of Christmas - 11 Restricting your API

12 Tips of Christmas - 11 Restricting your API

Yesterday we ended up with the following API. The one issue we have is that we've exposed all of our Post model regardless if we want to or not. 
module API
  module V1
    class Posts < Grape::API
      version 'v1'
      format :json

      resource :posts do
        desc "Return 10 most recent posts"

        get do
          Post.most_recent.limit(10)
        end

        desc 'Find a specific post'
        params do
          requires :id, type: Integer, desc: "The ID of the post"
        end
        get ':id' do
          Post.find(params[:id)
        end
      end

    end
  end
end
Grape provides an easy way to deal with this in the form of entities.
Under our V1 API directory, we're going to create a Post entity, that will restrict the information that comes out of our API
# app/controllers/api/v1/entities/post.rb
module API
  module V1
    module Entities
      class Post < Grape::Entity
        expose :content, documentation: { type: "String", desc: "The Post content"}
        expose :title, documentation: { type: "String", desc: "The Post title"}

        expose :description, documentation: { type: "String", desc: "The Post description" }

        format_with(:iso_timestamp) { |dt| dt.iso8601 }

        with_options(format_with: :iso_timestamp) do
          expose :created_at, documentation: { type: "DateTime", desc: "When the Post was posted"}
        end

        expose :comments, using: API::V1::Entities::Comments
      end
    end
  end
end
With use of the expose method, we can dictate what we do and don't return from our API, as well as provide documentation for users consuming our API. 
When working with building an API initially, I ran into an issue where the datetime returned by my API was different to what was initially coming into the database, the format_with method alleviates this by providing an easy way to declare a format to utilise on a particular attribute, which is picked up in the with_options block.
Finally as our post has many comments we can also expose those to an API request and utilise another entity again to control what of the comment data we return.

Saturday, 20 December 2014

12 Tips of Christmas - 10 Building an API with Grape

12 Tips of Christmas - 10 Building API's with Grape

As I work more and more with Ember, grasping onto well structured API's becomes increasingly valuable. Thanks to Grape, building an API out of your Rails application is very easy.
To start, add grape to your Gemfile, like so and run bundle install
gem "grape"
As we're ultimately serving up a response to requests from the client, we're going to house our API in our controllers directory. As Grape supports versioned API's we're going to keep that structure in place when we begin to create our API. So, first things first, let's create a base.rb file to mount our versioned API's
# app/controllers/api/base.rb

module API
  class Base < Grape::API
    mount API::V1::Base
  end
end
Now let's create our other base.rb file in our V1 directory so we can mount the resources this version of the API will support.
# app/controllers/api/v1/base.rb

module API
  class Base < Grape::API
    mount API::V1::Users
    mount API::V1::Posts
  end
end
Let's also setup our routes to support our new API
# config/routes.rb

mount API::Base => '/api'
This makes our users and posts API available at http://localhost:3000/api/v1/users.json and http://localhost:3000/api/v1/posts.json respectively (assuming you're exporting out JSON).
So let's take a look at what our API's might look like:
module API
  module V1
    class Posts < Grape::API
      version 'v1'
      format :json

      resource :posts do
        desc "Return 10 most recent posts"

        get do
          Post.most_recent.limit(10)
        end

        desc 'Find a specific post'
        params do
          requires :id, type: Integer, desc: "The ID of the post"
        end
        get ':id' do
          Post.find(params[:id)
        end
      end

    end
  end
end
In this very simple example, we declare the version and the format in which we will return.
We also declare the resource we're going to work with, along with our two GET requests we accept, one that returns the 10 most recent posts and one that will return a post determined by the id parameter supplied.
You'll notice that this is starting to look alot like our regular controllers, as well it should. We can also expand on this to start allowing users to make POST and PATCH requests as well.
With our params block , we can specify what parameters we accept as well as in what format they should come, much like Rails' strong parameters.
We also have the ability to document our API as we go with our description methods, this is far far easier to do as you're building up the API so I highly encourage you to do it as you go.
In the next post we'll take a look at restricting the data coming back out of our API

Friday, 19 December 2014

12 Tips of Christmas - 9 Custom Generators

Twelve Tips of Christmas - 9 Custom Generators

With an application template and the assistance of a gem, bootstrapping a brand new Rails app is very easy for us these days. I hadn't realised how spoilt we had become until I had to create one from scratch recently.

One of the nice things in our bootstrap process, is that I have a few generators running to install some custom templates for our application to utilise. Creating a generator command is pretty easy and can be done within a gem or within your own Rails app

We'll use our basic example which is to copy our usual Capistrano configuration templates over to our application folder:

Firstly, you'll need to extend Rails::Generators::Base and give it the root directory of your templates to copy over

class CapistranoConfigGenerator < Rails::Generators::Base
  source_root File.expand_path("../../templates", __FILE__)
end

Then its as simple as creating your methods and using the Thor API to start moving your files over:

class CapistranoConfigGenerator < Rails::Generators::Base
  source_root File.expand_path("../../templates", __FILE__)

  def copy_config_files
    copy_file "config/deploy.rb", "config/deploy.rb"
    directory "config/deploy", "config/deploy"
  end
end

Passing in an additional description, will help new users determine what your generator actually does if they dont happen to look at your code

class CapistranoConfigGenerator < Rails::Generators::Base
  source_root File.expand_path("../../templates", __FILE__)

  desc 'Copies over Capistrano templates'
  def copy_config_files
    copy_file "config/deploy.rb", "config/deploy.rb"
    directory "config/deploy", "config/deploy"
  end
end

The help can be viewed by running (assuming your generator is housed in your Rails application): bin/rails generate capistrano_config --help

Following that, just running the generate command and it'll safely start moving over those files for you

`bin/rails generate capistrano_config`

The flexibility and scope of Thor makes it really easy to accomplish any bootstrapping you may need to do, I highly recommend checking out the documentation

Thursday, 18 December 2014

12 Tips of Christmas - 8 Send Emails with Sidekiq

12 Tips of Christmas - 8 Send Emails with Sidekiq

To help ensure users get a fast experience within your application, one tool you can utilise is Sidekiq to process any sending of email you might be doing asynchronously. 
To get started, just add the following line to your Gemfile
gem 'sidekiq'
You'll also need redis, so if you haven't got that installed run the following:
$ brew update

$ brew install redis

$ redis-server /usr/local/etc/redis.conf
To run Sidekiq:
$ bundle exec sidekiq
Sidekiq supports sending emails with ActionMailer off the bat, all you need to do is call delay before your mailer method instead of using deliver eg:
UserMailer.delay.reminder(@user)
We can also call delay_until to delay the email send until a specified time.
All too easy

Wednesday, 17 December 2014

12 Tips of Christmas - 7 Inversion of Control

12 Tips of Christmas - 7 Inversion of Control

A lot of my posts in this series tend to revolve around a common theme, refactoring. When extracting a class, or method, you should look to inversion of control to make testing, and identification of dependencies easier.
Suppose we had a class like this:
class Receipt
  def mark_purchase
    @purchase = Purchase.latest.first
    enter_purchase_amount @purchase.amount
  end
end
By returning an instance of purchase within the method, we have created an implicit dependency on Purchase, this also makes it harder to test the method without first requiring an instance of the Purchase model. On top of this, we are now tied to the Purchase API, when all we wanted is something that would respond to amount.
Fixing this is easy.
class Receipt
  attr_reader :purchase

  def initialize purchase
    @purchase = purchase
  end

  def mark_purchase
    enter_purchase_amount purchase.amount
  end
end
Now when we instantiate our object, we can give it an instance of any object, so long as that object responds to the amount method, giving us some great flexibility
On top of that, our class can now be decoupled from ActiveRecord within our tests, as all we need to do is provide a test double for a purchase object.
One other benefit is that now, our dependency on purchase is explicit, this assists with future maintainers as they will be able to quickly identify it rather than get surprised down the road.
Of course this example is overtly simple, in our object if we didn't require any other reference to purchase, it would be far simpler to just pass in our amount as a dependency. This example, does however illustrate that by moving the responsibility of assigning the dependency up the chain, we've gained an interface thats more flexible, easier to maintain and easier to test.

Tuesday, 16 December 2014

12 Tips of Christmas - 6 Decorators

One of the really nice things about working with Ember is that every part nicely encapsulates it's level of responsibility. With Rails, this can be a harder proposition, especially when dealing with the view layer. Decorators can alleviate this issue and form our 6th, valuable tip.
We can utilise decorators to move view related logic out of the model, or helper and into the decorator object, we can do this, using SimpleDelegator.
SimpleDelegator accepts an object as part of it's instantiation, and if it can't find a method it will delegate to the underlying object.
class UserDecorator < SimpleDelegator
  def full_title
    "#{title} #{first_name} #{last_name}"
  end
end


class UsersController < ApplicationController
  def show
    @user = UserDecorator.new(User.find(params[:id])
  end
end
Using decorators as a view object, is a very simple option for moving logic out of the business layer that is the model.
Extending this concept, methods within the model that don't explicitly relate to business logic can be moved out and repurposed in a decorator.
class UsersController < ApplicationController
  def index
    @users = UsersDecorator.new(User.all).latest_users
  end
end
The question of where and when to extract this logic, should be dictated by whether or not it falls outside of the responsibility of the object you might decorate it with. I'm a big believer in trying to adhere to Single Responsibility Principle, so this extraction makes a lot of sense.
We want to utilise SimpleDelegator rather than sub-classing our objects as we're not really interested in copying or exposing the base classes API, we just want to copy functionality.