Reputation: 11
Our API shall return JSON objects (but not JSON API). How can we change the ActiveModel::Serializer to create a JSON object with data property set to null?
The response we get for an empty (has_one relationship) resource is NULL, but we expect it to be in a JSON format {data: NULL} just as we receive for a non-empty resource {data: {...}}, or for a list (has_many relationship) resource {data: []}.
We use ActiveModel::Serialiser and specify the key to be named "data" instead of the resource name (similar to JSON API, but the content of data is a direct JSON representation of the entity).
Models:
class User < ApplicationRecord
has_one :profile
def serializer_class
V1::UserSerializer
end
end
class Profile < ApplicationRecord
belongs_to :user
def serializer_class
V1::ProfileSerializer
end
end
Serializers:
class ApplicationSerializer < ActiveModel::Serializer
def json_key
'data'
end
end
class UserSerializer < ApplicationSerializer
attributes :id, :created_at, :updated_at #we do not include the profile here
end
class ProfileSerializer < ApplicationSerializer
attributes :id, :created_at, :updated_at
end
Controllers:
class ProfilesController < ::ApplicationController
before_action :authenticate_user!
def show
@profile = current_user.profile
render json: @profile
end
end
Responses:
We get a (for us wrong) response for an empty resource (GET /profile):
NULL
We correctly get a response for a non-empty resource, it looks like this (not JSON API):
{
data: {
id: ...,
createdAt: ...,
updatedAt: ...
}
}
We expect the response to be formatted like this in case that there is no entity associated (yet):
{
data: null
}
Upvotes: 1
Views: 1760
Reputation: 11
We decided to go for this more strict solution, where we respond with 404 for an empty resource.
def show
@profile = current_user.profile
raise ActiveRecord::RecordNotFound unless @profile
render json: @profile
end
And in the ApplicationController we add this to handle the exception:
rescue_from ActiveRecord::RecordNotFound do |exception|
render json: Api::ErrorSerializer.serialize(:not_found, 'Not Found'),
status: :not_found
end
Upvotes: 0
Reputation: 11
I found this (workaround) solution solves the problem:
def show
@profile = current_user.profile
if @profile
render json: @profile
else
render json: { data: nil }
end
end
Upvotes: 0