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
orunless
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.