I was playing around with ActiveResource from the edge rails revision
6032, and had a nightmare trying to get returned errors from my
RESTful controller.
After a long search, I found out in here: http://dev.rubyonrails.org/
browser/trunk/activeresource/test/base_errors_test.rb?rev=6032
on line 7 that you supposed to return http status code 422 along with
your error xml!!
so suppose you have code like this:
format.xml { render :xml => @user.errors.to_xml }
active resource will die horribly!!
The correct way is format.xml { render :xml =>
@user.errors.to_xml, :status => 422 }
I was curious about what is this mysterious status code, so I searched
in google, wikipedia, etc...
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415(Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous XML instructions.
In this case WebDAV defined a status code to deal with the
case where a request contains information that can be parsed
but is contains invalid information.
Its considered good practice to reuse registered status codes
(even those from RFC's other than 2616) rather than inventing
your own, provided they fit your needs. In this case 422 is
a perfect fit when you want to tell the client that the data
they submitted was parsed, but found to be invalid.
So, wait.... we're supposed to always return 422 for a REST request that
has errors?
Or, as the OP said:
<snip>
so suppose you have code like this:
format.xml { render :xml => @user.errors.to_xml }
active resource will die horribly!!
The correct way is format.xml { render :xml =>
@user.errors.to_xml, :status => 422 }
</snip>
Never mind the numeric code versus the names (I have just as hard a time
remembering the names as the numerics, by the way)... it sounds like
scaffold_resource isn't doing the full job for us. (I've given up on
to_xml too... it never gives me enough control).
Thanks for the information, guys, that helped me out alot.
I didn't want to use :status => 422 either, it's somewhat ugly...
Yes, I think for ActiveResource to properly hand error messages, the
RESTful controller needs to send :status => :unprocessable_entity
whenever you use model.errors.to_xml. Example:
def create
@person = Person.new(params[:person])
respond_to do |format|
if @person.save
format.html { redirect_to person_path(@person) }
format.xml { head :created, :location => person_url(@person) }
else
format.html { render :action => 'new' }
format.xml { render :xml => @person.errors.to_xml :status
=> :unprocessable_entity }
end
end
So, wait.... we're supposed to always return 422 for a REST request that
has errors?
The short answer to your question is: Yes, when a model is invalid
the best status code to return is 422.
More broadly, there are many different reasons to return an error,
422 is only useful for one specific kind. Whenever the client
sends something in the request the server likes you can return
any of the 4xx status codes...
It could be anything from submitting a request to a URL that
doesn't exist (404) or has been explicitly deleted (410). Maybe
the URL is too long to be handled (414) or maybe the method isn't
allowed (405). Maybe the request can be parsed, but the data you get
after parsing is invalid (422). There's more in the IANA status code
registry but you get the idea:
Even though a well designed client will treat any 4xx status that
it doesn't understand as 400, I still wouldn't use 400 unless there
was no other 4xx status code in the registry that matches.
When you use a more specific error status code you give the client
(browser, bot, etc) a better indication of what went wrong, improving
the odds that it can self-recover without human intervention.
so suppose you have code like this:
format.xml { render :xml => @user.errors.to_xml }
active resource will die horribly!!
The correct way is format.xml { render :xml =>
@user.errors.to_xml, :status => 422 }
it sounds like scaffold_resource isn't doing the full job for us.
(I've given up on to_xml too... it never gives me enough control).
The scaffold_resource should probably be updated to use 422, but I
agree: I don't think to_xml like the above example is too useful
except in the uncommon case (for me) where I only have a single
model object in an action.