Entities for Representation

Grape provides a powerful mechanism for controlling the representation of your data in API responses through Entities. This allows you to separate your internal data models from the JSON or XML structure you expose to clients, ensuring a clean and consistent API.

The grape-entity gem provides this functionality and is a common companion to Grape.

Using present

The present method is the core of Grape's representation layer. It takes an object and an options hash, which can include a :with key to specify the entity to use.

class UserAPI < Grape::API
  get '/users/:id' do
    user = User.find(params[:id])
    present user, with: API::Entities::User
  end
end

Defining an Entity

An entity is a class that inherits from Grape::Entity and uses the expose method to declare which attributes of an object should be included in the response.

module API
  module Entities
    class User < Grape::Entity
      # Expose the `name` and `email` attributes of the User object
      expose :name, :email

      # Expose a calculated value
      expose :digest do |user, options|
        Digest::MD5.hexdigest(user.email)
      end

      # Expose a related object using another entity
      expose :statuses, using: API::Entities::Status

      # Conditionally expose an attribute
      expose :ip_address, if: { type: :full }
    end
  end
end

Key Features of Entities:

  • Conditional Exposure: Use if or unless with a hash or lambda to conditionally include fields.
  • Nested Entities: Expose associated objects using other entities with the using option.
  • Calculated Fields: Define a block for an expose call to compute a value on the fly.
  • Root Keys: Define root keys for single objects and collections using root.
  • Documentation: Entities can generate documentation for parameters, which can be used in your desc blocks.

Automatic Entity Detection

Grape can automatically detect which entity to use. If you have a model User and define an entity User::Entity, Grape will automatically use it when you call present User.new.

# app/models/user.rb
class User
  # ... attributes ...

  class Entity < Grape::Entity
    expose :name, :email
  end
end

# In your API:
get '/users/:id' do
  user = User.find(params[:id])
  # No need for `with: User::Entity`, it's detected automatically
  present user
end

Using Entities for Parameter Documentation

You can reuse your entity definitions to document your parameters, ensuring consistency between your input and output formats.

class StatusAPI < Grape::API
  desc 'Create a status' do
    # Use the entity's documentation for the params description
    params API::Entities::Status.documentation.except(:id)
  end
  params do
    # Use the entity to define the actual parameters
    requires :all, except: [:id], using: API::Entities::Status.documentation
  end
  post '/status' do
    Status.create!(declared(params))
  end
end

Other Serialization Libraries

While grape-entity is tightly integrated, you can also use other popular serialization libraries with Grape:

  • Roar: For hypermedia formats like HAL. Use the grape-roar gem.
  • Rabl: Use the grape-rabl gem.
  • Active Model Serializers: Use the grape-active_model_serializers gem.