6
votes

So, I am writing Rails web application which has JSON API for mobile apps. For example, it sends POST JSON request to example.com/api/orders to create order.

{id: 1, order: { product_name: "Pizza", price: 10000}}

In case of validation errors I can response with HTTP 422 error code and order.errors.full_messages in json. But it seems better for me to have specific error code in JSON response. Unfortunately, it seems like Rails does not provide ability to set error code for validation error. How to solve this problem?

3

3 Answers

6
votes

You can pass a custom status code by using the status option when rendering the response.

def create
  @order = ...

  if @order.save
    render json: @order
  else
    render json: { message: "Validation failed", errors: @order.errors }, status: 400
  end
end

I usually tend to return HTTP 400 on validation errors. The message is a readable status response, the errors are also attached.

This is a respons example

{
    message: "Validation failed",
    errors: [
        ...
    ]
}

You can also embed additional attributes.

1
votes

I was after something similar, so what I did was extend String eg

class ErrorCodeString < String
  def init(value, error_code)
     @error_code = error_code
     super(value)
  end

  def error_code
      @error_code
  end
end

Then in a custom validation (this won't work on standard validation) I'd do

 errors.add(:email, ErrorCodeString.new('cannot be blank', 50)

Now when you return your JSON you can check to see if the error value is an ErrorCodeString and add the error_code value to the output. As ErrorString inherits String, you shouldn't be breaking anything else along the way.

1
votes

Rails 5 has error.details that can be used for exactly that.

In the model

errors.add(:price, 1023, message: "Transaction value #{price} is above limit (#{maximum_price}).")

In the controller

format.json { render json: @order.errors.details, status: :unprocessable_entity }

error details can be anything, eg. you could also use :above_limit instead of 1023. The API response body will then look like

pp JSON.parse(response)
{"price"=>[{"error"=>1023}]}

This feature has been backported to Rails 4, see also http://blog.bigbinary.com/2016/05/03/rails-5-adds-a-way-to-get-information-about-types-of-failed-validations.html

Also: Is there a way to return error code in addition to error message in rails active record validation?