- Grape::ActiveModelSerializers
- Installation
- Dependencies
- Usage
- Require grape-active_model_serializers
- Tell your API to use Grape::Formatter::ActiveModelSerializers
- Writing Serializers
- Serializers are inferred by active_record model names
- Array Roots
- API Versioning
- Manually specifying serializer / adapter options
- Error Serialization
- Custom Metadata
- Default Serializer Options
- Current User
- Full Example
- Swagger Documentation
- Contributing
- History
Use active_model_serializers with Grape!
Add the grape and grape-active_model_serializers gems to Gemfile and run bundle install.
gem 'grape-active_model_serializers'See UPGRADING if you're upgrading from a previous version.
- >= Ruby v3.1
- >= grape v2.3.0
- >= active_model_serializers v0.10.0
CI covers Grape 2.3, 2.4, 3.0, the latest 3.x, and 4.x on compatible Ruby versions through Ruby 4.0. Grape 4.x is tested on Ruby 3.3 and newer. See CONTRIBUTING for local matrix commands.
# config.ru
require 'grape-active_model_serializers'class API < Grape::API
format :json
formatter :json, Grape::Formatter::ActiveModelSerializers
error_formatter :json, Grape::ErrorFormatter::ActiveModelSerializers
endgrape-active_model_serializers will search for serializers for the objects returned by your grape API.
namespace :users do
get ":id" do
@user = User.find(params[:id])
end
endIn this case, as User objects are being returned, grape-active_model_serializers will look for a serializer named UserSerializer.
When serializing an array, the array root is set to the innermost namespace name if there is one, otherwise it is set to the route name.
In the following API the array root is users.
namespace :users do
get ":id" do
@user = User.find(params[:id])
end
endIn the following example the array root is people.
get "people" do
@user = User.all
endIf your Grape API is versioned you must namespace your serializers accordingly.
For example, given the following API.
module CandyBar
class Core < Grape::API
version 'candy_bar', using: :header, vendor: 'acme'
end
end
module Chocolate
class Core < Grape::API
version 'chocolate', using: :header, vendor: 'acme'
end
end
class API < Grape::API
format :json
formatter :json, Grape::Formatter::ActiveModelSerializers
mount CandyBar::Core
mount Chocolate::Core
endNamespace your serializers according to each version.
module CandyBar
class UserSerializer < ActiveModel::Serializer
attributes :first_name, :last_name, :email
end
end
module Chocolate
class UserSerializer < ActiveModel::Serializer
attributes :first_name, :last_name
end
endThis keeps serializers organized.
app
└── api
├── chocolate
└── core.rb
└── candy_bar
└── core.rb
api.rb
└── serializers
├── chocolate
└── user_serializer.rb
└── candy_bar
└── user_serializer.rb
Or as follows.
└── serializers
├── chocolate_user_serializer.rb
└── candy_bar_user_serializer.rb
ActiveModelSerializer will fetch automatically the right serializer to render.
# Serializer and adapter options can be specified on routes or namespaces.
namespace 'foo', serializer: BarSerializer do
get "/" do
# will use "bar" serializer
end
# Options specified on a route or namespace override those of the containing namespace.
get "/home", serializer: HomeSerializer do
# will use "home" serializer
end
# All standard options for `ActiveModel::Serializers` are supported.
get "/fancy_homes", root: 'world', each_serializer: FancyHomesSerializer
...
end
end# Serializer and adapter options can also be specified in the body of the route
resource :users do
get '/:id' do
if conditional
# uses UserSerializer and configured default adapter automatically
current_user
else
# uses specified serializer and adapter
render current_user, serializer: ErrorSerializer, adapter: :attributes
end
end
end# Adhoc serializer options can be specified in the body of the route
resource :users do
get '/:id' do
render current_user, extra: { adhoc_name_option: 'value' }
end
end
class UserSerializer
def name
instance_options[:adhoc_name_option] # accessible in instance_options
end
endUse Grape::ErrorFormatter::ActiveModelSerializers for errors, not Grape::Formatter::ActiveModelSerializers, which formats successful responses. The error formatter serializes an invalid model with ActiveModel::Serializer::ErrorSerializer.
Pass the model itself to error!, not model.errors. A failed ActiveRecord update returns false; it does not invoke the error formatter automatically.
ActiveModelSerializers.config.adapter = :json_api
class API < Grape::API
format :json
formatter :json, Grape::Formatter::ActiveModelSerializers
error_formatter :json, Grape::ErrorFormatter::ActiveModelSerializers
params do
requires :id, type: String
optional :first_name, type: String
end
patch '/users/:id' do
user = User.find(params[:id])
attributes = declared(params, include_missing: false).except(:id)
error!(user, 422) unless user.update(attributes)
user
end
endWith the :json_api adapter, validation failures return HTTP 422 with a JSON:API errors array. The response shape follows the configured ActiveModelSerializers adapter, not the Grape format name: the example still uses format :json. Setting the global adapter also affects successful responses.
# Control any additional metadata using meta and meta_key
get "/homes"
collection = Home.all
render collection, { meta: { page: 5, current_page: 3 }, meta_key: :pagination_info }
endDefine default_serializer_options as a Grape helper to supply options for each request. AMS 0.10 uses fields for attribute filtering, not the legacy only/except options; exclude is not a supported filtering option either.
helpers do
def default_serializer_options
{ fields: params[:fields] }
end
end
params do
optional :fields, type: [String]
end
get '/users' do
User.all
endFor the :attributes and :json adapters, a request such as /users?fields[]=first_name selects only first_name from the serializer's attributes. Omitting fields leaves the attributes unchanged. Namespace and route options override defaults with the same key.
The :json_api adapter instead expects a hash keyed by resource type, for example { fields: { users: [:first_name, :last_name] } }. See the AMS JSON:API adapter documentation for adapter-specific options.
One of the nice features of ActiveModel::Serializers is that it provides access to the authorization context via the current_user.
In Grape, you can get the same behavior by defining a current_user helper method.
helpers do
def current_user
@current_user ||= User.where(access_token: params[:token]).first
end
def authenticate!
error!('401 Unauthenticated', 401) unless current_user
end
endThen, in your serializer, you could show or hide some elements based on the current user's permissions.
class PostSerializer < ActiveModel::Serializer
def include_admin_comments?
current_user.roles.member? :admin
end
endNote: in the 0.9.x stable version of active model serializers, you have to access current user on scope - so scope.current_user.
class User < ActiveRecord::Base
attr_accessor :first_name, :last_name, :password, :email
end
class UserSerializer < ActiveModel::Serializer
attributes :first_name, :last_name
end
class API < Grape::API
get("/home") do
User.new({first_name: 'JR', last_name: 'HE', email: 'contact@jrhe.co.uk'})
end
end
API.new.get "/home" # => '{ user: { first_name: "JR", last_name: "HE" } }'Swagger generation is optional and provided by grape-swagger, not by this gem. The third-party grape-swagger-active_model_serializers gem registers an AMS model parser, analogous to the Entity and Representable integrations.
Add the documentation dependencies to your application's Gemfile:
gem 'grape-active_model_serializers'
gem 'grape-swagger'
gem 'grape-swagger-active_model_serializers'Load the parser before generating the documentation and identify the serializer as the endpoint's success model:
require 'grape-active_model_serializers'
require 'grape-swagger-active_model_serializers'
class UserSerializer < ActiveModel::Serializer
attributes :id, :name
end
class API < Grape::API
format :json
formatter :json, Grape::Formatter::ActiveModelSerializers
desc 'Return a user', success: UserSerializer
get '/users/:id' do
render User.find(params[:id]), serializer: UserSerializer, adapter: :attributes
end
add_swagger_documentation
endGET /swagger_doc returns the Swagger/OpenAPI 2.0 document with a generated definition for the serializer's attributes. success: UserSerializer selects the documentation model; it does not configure response serialization, so keep the runtime serializer and adapter consistent with the schema.
The example uses the :attributes adapter to match a flat object schema. A serializer definition alone does not describe a :json root envelope, JSON:API's data/included structure, or relationships. Attribute types depend on the parser's model metadata and untyped attributes may default to strings. Inspect the generated definitions and use custom model parsers or explicit response models when your output needs a different schema.
The parser is maintained separately, brings its own dependencies, and is not required for normal serialization. Check its documentation and compatibility when choosing versions.
See CONTRIBUTING.
Structured and based upon grape-rabl.