-
-
Save abinoam/762802f4f48e9d1aa98d48940b2fd724 to your computer and use it in GitHub Desktop.
A read-only frontend API abstraction applicable to any application.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Api | |
module V1 | |
# Controller to consume read-only data to be used on client's frontend | |
class FrontEndController < ActionController::API | |
include Orderable | |
# GET /:resource | |
# GET /:resource.json | |
def index | |
render json: ransack_result.paginate(page: params[:page], per_page: params[:per_page]) | |
.to_json(include: params[:include]&.split(',')) | |
end | |
# GET /:resource/1 | |
# GET /:resource/1.json | |
def show | |
render json: object.to_json(include: params[:include]&.split(',')) | |
end | |
# GET /:resource/1/:nested | |
# GET /:resource/1/:nested.json | |
alias nested_index index | |
# OPTIONS /:resource | |
# OPTIONS /:resource.json | |
# OPTIONS /:resource/1/:nested | |
# OPTIONS /:resource/1/:nested.json | |
def schema | |
render json: schemated.to_json | |
end | |
private | |
# Common setup to stablish which model is the resource of this request | |
def resource | |
@resource ||= params[:resource].classify.constantize | |
end | |
# Common setup to stablish which object this request is querying | |
def object | |
resource_id = params[:id] | |
@object ||= if resource.respond_to?(:friendly) | |
resource.friendly.find(resource_id) | |
else | |
resource.find(resource_id) | |
end | |
end | |
# Setup to stablish the nested model to be queried | |
def nested | |
@nested ||= object.send(params[:nested]) | |
end | |
# Used to setup the resource's schema | |
def schemated | |
raise ActionController::BadRequest('Invalid resource') unless records.present? | |
@schemated ||= {}.tap do |schemated| | |
records.columns_hash.each { |key, value| schemated[key] = value.type } | |
end | |
end | |
# Used to setup the records from the selected resource | |
# that are going to be rendered | |
def ransack_result | |
records.order(ordering_params(params)) | |
.ransack(JSON.parse(params[:q])).result | |
end | |
def records | |
@records ||= (params[:nested] ? nested : resource) | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
# This concern is used to provide abstract ordering based on `params[:sort]` | |
module Orderable | |
extend ActiveSupport::Concern | |
SORT_ORDER = { '+' => :asc, '-' => :desc }.freeze | |
# A list of the param names that can be used for ordering the model list | |
def ordering_params(params) | |
# For example it retrieves a list of orders in descending order of total_value. | |
# Within a specific total_value, older orders are ordered first | |
# | |
# GET /orders?sort=-total_value,created_at | |
# ordering_params(params) # => { total_value: :desc, created_at: :asc } | |
# | |
# Usage: | |
# Order.order(ordering_params(params)) | |
ordering = {} | |
params[:sort].try(:split, ',').try(:each) do |attr| | |
attr = parse_attr attr | |
model = controller_name.titlecase.singularize.constantize | |
if model.attribute_names.include?(attr) | |
ordering[attr] = SORT_ORDER[parse_sign attr] | |
end | |
end | |
ordering | |
end | |
private | |
# Parsing of attributes to avoid empty starts in case browser passes "+" as " " | |
def parse_attr(attr) | |
'+' + attr.gsub(/^\ (.*)/, '\1') if attr.starts_with?(' ') | |
end | |
# Ordering sign parse, which separates | |
def parse_sign(attr) | |
attr =~ /\A[+-]/ ? attr.slice!(0) : '+' | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
get '/:resource/', to: 'front_end#index', via: :get | |
get '/:resource/:id', to: 'front_end#show', via: :get | |
get '/:resource/:id/:nested/', to: 'front_end#nested_index', via: :get | |
match '/:resource/', to: 'front_end#schema', via: :options | |
match '/:resource/:id/:nested/', to: 'front_end#schema', via: :options |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment