class JsonApiServer::Builder

This class integrates JSON API features – pagination, sorting, filters, inclusion of related resources, and sparse fieldsets – in one place. It collects data to be used by serializers.

Usage:

The Builder class takes two arguments, (1) the controller request and (2) an initial query (i.e., MyModel.all, MyModel.authorized_to(current_user), etc.).

Add JSON API features appropriate for the request. These methods are chainable. Except for sparse fields, JSON API features are configured; filter, include and sort configurations whitelist attributes/behavior while pagination sets defaults and limits on number of records to return.

Once features are added, their corresponding values can be accessed:

Example
attr_accessor :pagination_options, :sort_options, :filter_options, :include_options

before_action do |c|
  c.pagination_options = { default_per_page: 10, max_per_page: 60 }
  c.sort_options = {
   permitted: [:character, :location, :published],
   default: { id: :desc }
  }
  c.filter_options = [
   { id: { type: 'Integer' } },
   { published: { type: 'Date' } },
   :location,
   { book: { wildcard: :both } }
  ]
  c.include_options = [
                        {'publisher': -> { includes(:publisher) }},
                        {'comments': -> { includes(:comments) }},
                       'comment.author'
                     ]
end

# A collection.
def index
  builder = JsonApiServer::Builder.new(request, Topic.current)
   .add_pagination(pagination_options)
   .add_filter(filter_options)
   .add_include(include_options)
   .add_sort(sort_options)
   .add_fields

 serializer = TopicsSerializer.from_builder(builder)
 render json: serializer.to_json, status: :ok
end

# A resource.
def show
  builder = JsonApiServer::Builder.new(request, Topic.find(params[:id]))
   .add_include(['publisher', 'comments', 'comments.includes'])
   .add_fields

  serializer = TopicSerializer.from_builder(builder)
  render json: serializer.to_json, status: :ok
end

Attributes

fields[R]

JsonApiServer::Fields instance if add_fields was called. nil otherwise.

filter[R]

JsonApiServer::Filter instance if add_filter was called. nil otherwise.

include[R]

JsonApiServer::Include instance if add_include was called. nil otherwise.

model[R]

ActiveRecord::Base model extracted from initial query passed in constructor.

pagination[R]

JsonApiServer::Pagination instance if add_pagination was called. nil otherwise.

request[R]

ActionDispatch::Request passed in constructor.

sort[R]

JsonApiServer::Sort instance if add_sort was called. nil otherwise.

Public Class Methods

new(request, query) click to toggle source

Arguments:

  • request - an ActionDispatch::Request

  • query (ActiveRecord::Relation) - Initial query.

# File lib/json_api_server/builder.rb, line 102
def initialize(request, query)
  @request = request
  @initial_query = query
  @model = model_from_query(@initial_query)
end

Public Instance Methods

add_fields() click to toggle source

Creates JsonApiServer::Fields instance based on request. Instance is available through the fields attribute.

# File lib/json_api_server/builder.rb, line 165
def add_fields
  @fields = JsonApiServer::Fields.new(request)
  self
end
add_filter(permitted = []) click to toggle source

Creates JsonApiServer::Filter instance based on request, initial query model and filter configs. Instance is available through the filter attribute.

# File lib/json_api_server/builder.rb, line 138
def add_filter(permitted = [])
  @filter = JsonApiServer::Filter.new(request, model, permitted)
  self
end
add_include(permitted = []) click to toggle source

Creates JsonApiServer::Include instance based on request, initial query model and include configs. Instance is available through the include attribute.

# File lib/json_api_server/builder.rb, line 148
def add_include(permitted = [])
  @include = JsonApiServer::Include.new(request, model, permitted)
  self
end
add_pagination(**options) click to toggle source

Creates JsonApiServer::Pagination instance based on request, initial query model and pagination options. Instance is available through the pagination attribute. For collections only.

# File lib/json_api_server/builder.rb, line 128
def add_pagination(**options)
  @pagination = JsonApiServer::Pagination.new(request, model, options)
  self
end
add_sort(**options) click to toggle source

Creates JsonApiServer::Sort instance based on request, initial query model and sort options. Instance is available through the sort attribute.

# File lib/json_api_server/builder.rb, line 158
def add_sort(**options)
  @sort = JsonApiServer::Sort.new(request, model, options)
  self
end
includes() click to toggle source

(Array or nil) Whitelisted includes. An array of relationships (strings) if add_include was called previously, nil otherwise. i.e,

['comments', 'comments.author']
# File lib/json_api_server/builder.rb, line 180
def includes
  @include.try(:includes)
end
paginator() click to toggle source

JsonApiServer::Paginator instance for collection if add_pagination was called previously, nil otherwise.

# File lib/json_api_server/builder.rb, line 172
def paginator
  @pagination.try(:paginator_for, relation)
end
query()
Alias for: relation
relation() click to toggle source

Merges pagination, filter, sort, and include sub-queries (if defined) into the initial query. Returns an ActiveRecord::Relation object.

# File lib/json_api_server/builder.rb, line 110
def relation
  @relation ||= begin
    return @initial_query unless @initial_query.respond_to?(:where)

    %i[pagination filter include sort].each_with_object(@initial_query) do |method, query|
      frag = send(method).try(:relation)
      query.merge!(frag) if frag
    end
  end
end
Also aliased as: query
sparse_fields() click to toggle source

(Hash or nil) Sparse fields. Available if add_fields was previously called. i.e.,

{'articles => ['title', 'body', 'author'], 'people' => ['name']}
# File lib/json_api_server/builder.rb, line 187
def sparse_fields
  @fields.try(:sparse_fields)
end

Protected Instance Methods

model_from_query(query) click to toggle source
# File lib/json_api_server/builder.rb, line 193
def model_from_query(query)
  if query.respond_to?(:klass)
    query.klass
  elsif query.respond_to?(:class)
    query.class
  end
end