Advanced Features

This guide covers advanced features of Ruby JSONAPI including caching, sparse fieldsets, and more.

Caching

Ruby JSONAPI supports resource-level caching to improve performance. When enabled, serializer instances will be cached based on the resource object’s cache key.

Enabling Caching

class MovieSerializer
  include JSONAPI::Serializer

  set_type :movie
  cache_options store: Rails.cache, namespace: 'jsonapi-serializer', expires_in: 12.hours
  attributes :name, :year, :rating
end

Cache Store Configuration

Ruby JSONAPI uses Rails’ cache store by default. In non-Rails applications, you need to configure a cache store:

cache_options store: ActiveSupport::Cache::MemoryStore.new, namespace: 'jsonapi-serializer', expires_in: 12.hours

Sparse Fieldsets

JSON:API allows clients to request only specific fields, reducing payload size:

serializer = MovieSerializer.new(
  movie,
  { fields: { movie: [:name], actor: [:name] } }
)

This limits the output to only include the specified fields:

{
  "data": {
    "id": "1",
    "type": "movie",
    "attributes": {
      "name": "Inception"
    }
  }
}

Helper Methods

You can define helper methods in your serializers for reuse:

class MovieSerializer
  include JSONAPI::Serializer

  attributes :name, :year

  attribute :director_name do |movie|
    get_full_name(movie.director)
  end

  attribute :producer_name do |movie|
    get_full_name(movie.producer)
  end

  # Helper method
  def get_full_name(person)
    "#{person.first_name} #{person.last_name}"
  end
end

Params

You can pass arbitrary parameters to the serializer, useful for conditional logic or dynamic values:

serializer = MovieSerializer.new(
  movie,
  { params: { current_user: current_user, admin_view: true } }
)

Access these parameters in your serializer:

class MovieSerializer
  include JSONAPI::Serializer

  attributes :name, :year

  attribute :sensitive_data do |movie, params|
    if params[:admin_view]
      {
        budget: movie.budget,
        revenue: movie.revenue,
        profit_margin: movie.profit_margin
      }
    end
  end

  attribute :can_edit do |movie, params|
    params[:current_user]&.can_edit?(movie) || false
  end
end

Instrumentation

Ruby JSONAPI supports performance instrumentation:

require 'jsonapi/serializer/instrumentation'

class MovieSerializer
  include JSONAPI::Serializer
  include JSONAPI::Serializer::Instrumentation

  # Enable instrumentation
  instrumentation_key :serialize

  attributes :name, :year
end

Custom Instrumenter

You can define a custom instrumenter:

module CustomInstrumenter
  def self.instrument(name, payload = {})
    start = Time.now
    yield
    duration = Time.now - start
    Rails.logger.info("#{name} took #{duration}ms")
  end
end

JSONAPI::Serializer.configure do |config|
  config.instrumenter = CustomInstrumenter
end
serializer = MovieSerializer.new(
  movie,
  {
    links: {
      self: 'https://api.example.com/movies',
      next: 'https://api.example.com/movies?page[offset]=2',
      last: 'https://api.example.com/movies?page[offset]=10'
    }
  }
)

Top-Level Meta

serializer = MovieSerializer.new(
  movie,
  {
    meta: {
      total: 100,
      pages: 10,
      page: 1
    }
  }
)

Collection Serialization Control

By default, jsonapi-serializer attempts to automatically detect if the provided resource is a collection. You can explicitly control this behavior:

# Force treat as a collection
MovieSerializer.new(resource, { is_collection: true })

# Force treat as a single resource
MovieSerializer.new(resource, { is_collection: false })

Deserialization

Ruby JSONAPI currently does not support deserialization (converting JSON:API requests into Ruby objects), but we recommend using one of the following gems for this functionality:

JSONAPI.rb

This gem provides the following features alongside deserialization:

  • Collection meta information
  • Error handling
  • Includes and sparse fieldsets
  • Filtering and sorting
  • Pagination

To use JSONAPI.rb for deserialization while using Ruby JSONAPI for serialization, you’ll need to configure both libraries in your application.