Project

General

Profile

« Previous | Next » 

Revision b2b47290

Added by Petr Chalupa almost 12 years ago

  • ID b2b4729059ff89327d7cd86d2e47664a2ce57c46

api v1 - render errors with rabl

better detection of permission failure in model
fix ApiConstraints
catch bad routes in api and return json

View differences:

app/controllers/api/base_controller.rb
respond_to :json
def process_error(options = { })
options[:json_code] ||= :unprocessable_entity
errors = if options[:error]
options[:error]
else
options[:object] ||= get_resource || raise("No error to process")
if options[:object].respond_to?(:errors)
#TODO JSON resposne should include the real errors, not the pretty full messages
logger.info "Failed to save: #{options[:object].errors.full_messages.join(", ")}"
options[:object].errors.full_messages
else
raise("No error to process")
end
end
# set 403 status on permission errors
if errors.any? { |error| error =~ /You do not have permission/ }
options[:json_code] = :forbidden
end
rescue_from StandardError, :with => lambda { |error|
Rails.logger.error "#{error.message} (#{error.class})\n#{error.backtrace.join("\n")}"
render_error 'standard_error', :status => 500, :locals => { :error => error }
}
def get_resource
instance_variable_get :"@#{resource_name}" or raise 'no resource loaded'
end
render :json => { "errors" => errors }, :status => options[:json_code]
def resource_name
controller_name.singularize
end
def resource_class
@resource_class ||= resource_name.camelize.constantize
end
protected
def process_resource_error(options = { })
resource = options[:resource] || get_resource
raise 'resource have no errors' if resource.errors.empty?
if resource.permission_failed?
deny_access
else
render_error 'unprocessable_entity', :status => :unprocessable_entity
end
end
def process_response(condition, response = nil)
def process_response(condition, response = get_resource)
if condition
response ||= get_resource
respond_with response
else
process_error
process_resource_error
end
end
......
if SETTINGS[:login]
unless User.current
user_to_login = nil
if result = authenticate_with_http_basic { |u, p| user_to_login = u; User.try_to_login(u, p) }
user_login = nil
result = authenticate_with_http_basic do |u, p|
user_login = u
User.try_to_login(u, p)
end
if result
User.current = result
else
process_error :error => "Unable to authenticate user %s" % user_to_login, :json_code => :unauthorized
render_error 'unauthorized', :status => :unauthorized, :locals => { :user_login => user_login }
return false
end
end
......
end
def deny_access
process_error :error => "Access denied", :json_code => :forbidden
render_error 'access_denied', :status => :forbidden
false
end
def get_resource
instance_variable_get :"@#{resource_name}" or raise 'no resource loaded'
end
def resource_name
controller_name.singularize
end
def resource_class
@resource_class ||= resource_name.camelize.constantize
end
protected
# searches for a resource based on its name and assign it to an instance variable
# required for models which implement the to_param method
#
......
def find_resource
finder, key = case
when (id = params[:"#{resource_name}_id"]).present?
[:find_by_id, id]
['id', id]
when (name = params[:"#{resource_name}_name"]).present?
[:find_by_name, name]
['name', name]
else
[nil, nil]
end
resource = resource_class.send(finder, key) if finder
if finder && resource
resource = resource_class.send(:"find_by_#{finder}", key) if finder
if resource
return instance_variable_set(:"@#{resource_name}", resource)
else
not_found and return false
render_error 'not_found', :status => :not_found, :locals => { :finder => finder, :key => key } and
return false
end
end
def not_found(exception = nil)
logger.debug "not found: #{exception}" if exception
head :status => 404
end
def set_default_response_format
request.format = :json if params[:format].nil?
end
......
end
end
def api_version
raise NotImplementedError
end
def render_error(error, options = { })
render options.merge(:template => "/api/v#{api_version}/errors/#{error}")
end
end
end

Also available in: Unified diff