Closed ljieyao closed 6 years ago
JSONAPI only requires that a top level errors array be returned and has many optional member attributes that you may or may not find useful:
http://jsonapi.org/format/#error-objects
Therefore you should just be able to make an error serializer with as much of the spec that you find useful (code, title, detail, for instance)
EDIT to add: Not my project, just wanted to help
@DVG thanks for chiming in and I agree with your approach. This library does not take an opinionated approach for serializing errors. You could optionally do something as simple as the below (untested) and still be within the json api spec.
data = { errors: [] }
data[:errors] << {id: "movie", title: "invalid title"}
render json: data, status: :unprocessable_entity
I feel like this question has been answered. I'm going to close this for now, please feel free to re-open if you disagree!
For anyone else reaching here like i did... i ended up implementing the following serializer. It supports nested model errors indexed. Manually tested, no rspec, so no guarantees
class ErrorSerializer
def initialize(model)
@model = model
end
def serialized_json
errors = @model.errors.messages.map do |field, errors|
errors.map do |error_message|
{
source: {pointer: "/data/attributes/#{field}"},
detail: error_message
}
end
end
@model.class.reflect_on_all_associations.each do |relationship|
@model.send(relationship.name).each_with_index do |child, index|
errors << child.errors.messages.map do |field, errors|
errors.map do |error_message|
{
source: {pointer: "/data/attributes/#{child.model_name.plural}[#{index}].#{field}"},
detail: error_message
}
end
end
end
end
errors.flatten
end
end
Additionally, if you like the JSONAPI error spec and want it for general use beyond errors within a model. You can drop something like this right in application_controller.rb
# CUSTOM GENERAL EXCEPTION HANDLING
# NOTE: This MUST come before any more specific exception handling. The order of definition is relevant!
rescue_from StandardError do |e|
logger.error "ApplicationController: GENERAL ERROR caught #{e}\n #{e.backtrace[0..5].join("\n")}"
respond_to do |format|
format.html { raise(e) }
format.json {
error_struct = {:errors => [
:status => '500',
:code => e.class.to_s,
:detail => e.message,
]}
render json: error_struct, status: :internal_server_error
}
format.pdf { Rails.env.development? ? raise(e) : redirect_to(root_path, :flash => { :error => "Error rendering page as PDF file" }) }
end
end
(I threw in PDF to demonstrate the env conditional which I often find useful during dev)
It would be awesome to have an implementation of the errors in json api format!
module Api::V1
class ApiController < ActionController::API
around_action :handle_errors
def handle_errors
yield
rescue ActiveRecord::RecordNotFound => e
render_api_error(e.message, 404)
rescue ActiveRecord::RecordInvalid => e
render_api_error(e.record.errors.full_messages, 422)
rescue JWT::ExpiredSignature => e
render_api_error(e.message, 401)
rescue InvalidTokenError => e
render_api_error(e.message, 422)
rescue MissingTokenError => e
render_api_error(e.message, 422)
end
def render_api_error(messages, code)
data = { errors: { code: code, details: Array.wrap(messages) } }
render json: data, status: code
end
end
end
This was the pattern we used for rendering errors for this gem, compliant with the JSON API spec.
Alternatively consider using the jsonapi.rb
gem which provides error handling for validation errors and other generic cases you can encounter:
https://github.com/stas/jsonapi.rb#error-handling
Since the work is heavily based on the fast_jsonapi
and the feedback I could find here (hence the small codebase), it should be easy to start using it.
Let me know if you have feedback as well :bowing_man:
Related issues #102 #408
@DVG thanks for chiming in and I agree with your approach. This library does not take an opinionated approach for serializing errors. You could optionally do something as simple as the below (untested) and still be within the json api spec.
data = { errors: [] } data[:errors] << {id: "movie", title: "invalid title"} render json: data, status: :unprocessable_entity
This is not JSON:API compatible actually From https://jsonapi.org/format/#errors-processing
Error objects MUST be returned as an array keyed by errors in the top level of a JSON:API document.
Sorry for chiming in this late
This is not JSON:API compatible actually From https://jsonapi.org/format/#errors-processing
Error objects MUST be returned as an array keyed by errors in the top level of a JSON:API document.
I think this is exactly why this library should implement errors.
I wonder how can I use it to return an error message with HTTP error?