Module: APIHelper::Fieldsettable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/api_helper/fieldsettable.rb
Overview
Helper To Make Resource APIs Fieldsettable
By making an API fieldsettable, you let API callers to choose the fields they wanted to be returned with query parameters. This is really useful for making API calls more efficient and fast.
This design made references to the rules of Sparse Fieldsets in JSON API: jsonapi.org/format/#fetching-sparse-fieldsets
A client can request that an API endpoint return only specific fields in the response by including a fields parameter, which is a comma-separated (“,”) list that refers to the name(s) of the fields to be returned.
GET /users?fields=id,name,avatar_url
This functionality may also support requests specifying multiple fieldsets for several objects at a time (e.g. another object included in an field of another object) with fields[object_type] parameters.
GET /posts?fields[posts]=id,title,author&fields[user]=id,name,avatar_url
Note: author of a post is a user.
The fields and fields[object_type] parameters can not be mixed. If the latter format is used, then it must be used for the main object as well.
Usage
Include this Concern in your Action Controller:
SamplesController < ApplicationController
include APIHelper::Fieldsettable
end
or in your Grape API class:
class SampleAPI < Grape::API
include APIHelper::Fieldsettable
end
then set the options for the fieldset in the grape method:
resources :posts do
get do
fieldset_for :post, root: true, default_fields: [:id, :title, :author]
fieldset_for :user, permitted_fields: [:id, :name, :posts, :avatar_url],
show_all_permitted_fields_by_default: true
# ...
end
end
This helper parses the fields and fields[object_type] parameters to determine what the API caller wants, and save the results into instance variables for further usage.
After this you can use the fieldset helper method to get the fieldset data that the request specifies.
With GET /posts?fields=title,author:
fieldset #=> { post: [:title, :author], user: [:id, :name, :posts, :avatar_url] }
With GET /posts?fields[post]=title,author&fields[user]=name:
fieldset #=> { post: [:title, :author], user: [:name] }
fieldset(:post) #=> [:title, :author]
fieldset(:post, :title) #=> true
fieldset(:user, :avatar_url) #=> false
You can make use of the information while dealing with requests, for example:
Post.select(fieldset(:post))...
If you’re using RABL as the API view, it can be also setup like this:
object @user
# this ensures the +fieldset+ instance variable is least setted with
# the default fields, and double check +permitted_fields+ at view layer -
# in case of things going wrong in the controller
set_fieldset :user, default_fields: [:id, :name, :avatar_url],
permitted_fields: [:id, :name, :avatar_url, :posts]
# determine the fields to show on the fly
attributes(*fieldset[:user])
Class Method Summary collapse
-
.fields_param_desc(example: nil) ⇒ Object
Return the ‘fields’ param description.
Instance Method Summary collapse
-
#fieldset(resource = nil, field = nil) ⇒ Object
Getter for the fieldset data.
-
#fieldset_for(resource, root: false, permitted_fields: [], show_all_permitted_fields_by_default: false, default_fields: []) ⇒ Object
Gets the fields parameters, organize them into a @fieldset hash for model to select certain fields and/or templates to render specified fieldset.
-
#set_fieldset(resource, default_fields: [], permitted_fields: []) ⇒ Object
View Helper to set the default and permitted fields.
Class Method Details
.fields_param_desc(example: nil) ⇒ Object
Return the ‘fields’ param description
164 165 166 167 168 169 170 |
# File 'lib/api_helper/fieldsettable.rb', line 164 def self.fields_param_desc(example: nil) if example.present? "Choose the fields to be returned. Example value: '#{example}'" else "Choose the fields to be returned." end end |
Instance Method Details
#fieldset(resource = nil, field = nil) ⇒ Object
Getter for the fieldset data
153 154 155 156 157 158 159 160 161 |
# File 'lib/api_helper/fieldsettable.rb', line 153 def fieldset(resource = nil, field = nil) if resource.blank? @fieldset ||= {} elsif field.blank? (@fieldset ||= {})[resource] ||= [] else fieldset(resource).include?(field) end end |
#fieldset_for(resource, root: false, permitted_fields: [], show_all_permitted_fields_by_default: false, default_fields: []) ⇒ Object
Gets the fields parameters, organize them into a @fieldset hash for model to select certain fields and/or templates to render specified fieldset. Following the URL rules of JSON API: jsonapi.org/format/#fetching-sparse-fieldsets
Params:
resource-
Symbolname of resource to receive the fieldset root-
Booleanshould this resource take the parameter fromfieldswhile no type is specified permitted_fields-
Arrayof Symbols list of accessible fields used to filter out unpermitted fields, defaults to permit all default_fields-
Arrayof Symbols list of fields to show by default show_all_permitted_fields_by_default-
Booleanif set to true, @fieldset will be set to all permitted_fields when the current resource’s fieldset isn’t specified
Example Result:
fieldset_for :user, root: true
fieldset_for :group
# @fieldset => {
# :user => [:id, :name, :email, :groups],
# :group => [:id, :name]
# }
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/api_helper/fieldsettable.rb', line 124 def fieldset_for(resource, root: false, permitted_fields: [], show_all_permitted_fields_by_default: false, default_fields: []) @fieldset ||= Hashie::Mash.new ||= Hashie::Mash.new # put the fields in place if params[:fields].is_a? Hash @fieldset[resource] = params[:fields][resource] || params[:fields][resource] elsif root @fieldset[resource] = params[:fields] end # splits the string into array of symbles @fieldset[resource] = @fieldset[resource].present? ? @fieldset[resource].split(',').map(&:to_sym) : default_fields # filter out unpermitted fields by intersecting them @fieldset[resource] &= permitted_fields if @fieldset[resource].present? && permitted_fields.present? # set default fields to permitted_fields if needed @fieldset[resource] = permitted_fields if show_all_permitted_fields_by_default && @fieldset[resource].blank? && permitted_fields.present? end |
#set_fieldset(resource, default_fields: [], permitted_fields: []) ⇒ Object
View Helper to set the default and permitted fields
146 147 148 149 150 |
# File 'lib/api_helper/fieldsettable.rb', line 146 def set_fieldset(resource, default_fields: [], permitted_fields: []) @fieldset ||= {} @fieldset[resource] = default_fields if @fieldset[resource].blank? @fieldset[resource] &= permitted_fields end |