response status when form validation fails

29 views
Skip to first unread message

Sok Ann Yap

unread,
Aug 18, 2008, 11:45:59 PM8/18/08
to pylons-...@googlegroups.com
Currently, the validate decorator always return 200 OK when validation
fails. I think 400 Bad Request is more appropriate here, so that it
will be easier for non-browser application to interact with the pylons
app. Maybe we can add a parameter to @validate that is defaulted to
200, to make it backward compatible.

The implication from the change is that we also need to remove 400
from the StatusCodeRedirect middleware. On a related note, the
following bits of code (from 0.9.7 beta5) seems to be inconsistent
with the comment:

# Display error documents for 401, 403, 404 status codes (and
# 500 when debug is disabled)
if asbool(config['debug']):
app = StatusCodeRedirect(app)
else:
app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])

Regards,
Yap

Jonathan Vanasco

unread,
Aug 19, 2008, 1:17:36 AM8/19/08
to pylons-discuss
i'm not sure if i like the idea of this.

the 400 error is for bad/malformed syntax and the request can't be
fulfilled.

in this situation, the http level request is most certainly understood
and authorized -- the error is in the application logic and should be
served on such -- not pushed into the http level.

a non-browser, or browser, app can just expect a json packet as such:

status: error / success
success: more info
error: detailed info or hash of info
additional_fields

and have all the information needed to intereact with pylons. i don't
see how saying that a 'good request' is a bad request will make things
easier.

Sok Ann Yap

unread,
Aug 19, 2008, 2:20:06 AM8/19/08
to pylons-...@googlegroups.com

Returning 400 for form validation error is recommended by Leonard
Richardson and Sam Ruby in the book RESTful Web Services. Here's an
excerpt from one of the examples in the book:

"If the client sends bad or incomplete data, the ActiveRecord
validation rules (defined in the User) model) fail, and the call to
User#save returns false. The response code then is 400 ("Bad
Request")."

Also, according to the specifications for OpenID and OAuth, both of
them return 400 for bad or missing parameters. I don't see any
difference between an OAuth service provider implemented using pylons
and my custom pylons web app. If the former shall return 400 for bad
or missing parameters, why can't the later?

By the way, structs has a bug report for the same issue that was
resolved as "Not A Problem", forcing their users to resort to
subclassing. So I guess it's OK if you don't like the idea :)

Regards,
Yap

Sok Ann Yap

unread,
Aug 19, 2008, 2:23:07 AM8/19/08
to pylons-...@googlegroups.com
> By the way, structs has a bug report for the same issue that was
> resolved as "Not A Problem", forcing their users to resort to
> subclassing.

Of course, I mean struts instead of structs. Here's the URL:
https://issues.apache.org/struts/browse/STR-2119

Lawrence Oluyede

unread,
Aug 19, 2008, 3:08:51 AM8/19/08
to pylons-...@googlegroups.com
On Tue, Aug 19, 2008 at 8:20 AM, Sok Ann Yap <sok...@gmail.com> wrote:
> Returning 400 for form validation error is recommended by Leonard
> Richardson and Sam Ruby in the book RESTful Web Services. Here's an
> excerpt from one of the examples in the book

Also if they didn't say it... it's just that 200 OK is plain wrong to
signal an error condition.
That's what 4xx and 5xx codes are for.


--
Lawrence, stacktrace.it - oluyede.org - neropercaso.it
"It is difficult to get a man to understand
something when his salary depends on not
understanding it" - Upton Sinclair

Jorge Vargas

unread,
Aug 19, 2008, 5:17:28 AM8/19/08
to pylons-...@googlegroups.com
On Tue, Aug 19, 2008 at 1:08 AM, Lawrence Oluyede <l.ol...@gmail.com> wrote:
>
> On Tue, Aug 19, 2008 at 8:20 AM, Sok Ann Yap <sok...@gmail.com> wrote:
>> Returning 400 for form validation error is recommended by Leonard
>> Richardson and Sam Ruby in the book RESTful Web Services. Here's an
>> excerpt from one of the examples in the book
>
> Also if they didn't say it... it's just that 200 OK is plain wrong to
> signal an error condition.
> That's what 4xx and 5xx codes are for.
>
Even though I agree in principle, there is no 4xx code to signal an
"error in the value of the parameters", please remember that http is a
transport protocol, and from that perspective it was a successful
transfer. I believe that trying to return http status codes for
application logic is violating the TCP layer division that has held us
in place for so long.

Building up on the json example, it should be read as, the request was
successful and everything when ok (http:200) now it seems you fail
with supplying the correct values (statusCode:xxx)

as for the webservices reference, I don't think that applies to
web-browsers, they could even interpret the 400 as something totally
different.

That said if enough people find this useful I'll say add a config
option where you can switch it and leave it as 200 for default.

Lawrence Oluyede

unread,
Aug 19, 2008, 5:43:41 AM8/19/08
to pylons-...@googlegroups.com
On Tue, Aug 19, 2008 at 11:17 AM, Jorge Vargas <jorge....@gmail.com> wrote:
>
> On Tue, Aug 19, 2008 at 1:08 AM, Lawrence Oluyede <l.ol...@gmail.com> wrote:
>>
>> On Tue, Aug 19, 2008 at 8:20 AM, Sok Ann Yap <sok...@gmail.com> wrote:
>>> Returning 400 for form validation error is recommended by Leonard
>>> Richardson and Sam Ruby in the book RESTful Web Services. Here's an
>>> excerpt from one of the examples in the book
>>
>> Also if they didn't say it... it's just that 200 OK is plain wrong to
>> signal an error condition.
>> That's what 4xx and 5xx codes are for.
>>
> Even though I agree in principle, there is no 4xx code to signal an
> "error in the value of the parameters", please remember that http is a
> transport protocol, and from that perspective it was a successful
> transfer. I believe that trying to return http status codes for
> application logic is violating the TCP layer division that has held us
> in place for so long.

I disagree. TCP is the transport protocol (which resides at the
transport level of the stack).
HTTP is an application protocol (which resides on top of the stack),
and I'm pretty sure that
the creators of HTTP intended to use 400 BAD REQUEST also for such
cases. As the spec says:

" The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications. "

Nothing forbids to explain _why_ in the body of the response but if
you want to create a seamless web where 200 means "ok what you asked
worked correctly"
returning 200 for an error is not the most compatible way to go.
Remember also there are automatic clients, non-desktop-web clients,
mobile browsers and so on.
If you want maximum compatibility I think that returning an error code
for an error situation is not also smart to do but should be
mandatory.

There is really no point in returning a OK status code with something
that didn't go as it should.

Imagine a situation when I do subsequently PUT of a resource like
/book/summer. If the server replied 200 with a wrong content (or wrong
content type) how do I know
that I'm doing something wrong? Looking at the body searching for the
"error" word is not feasible, that's what status codes are for.

> Building up on the json example, it should be read as, the request was
> successful and everything when ok (http:200) now it seems you fail
> with supplying the correct values (statusCode:xxx)

So the request did not suceed because the GOAL was not to test that
the server is there and alive but that the next time I access to the
resource it will be there.
Not that I'll found out in 10 minutes that the request I made 10
minutes ago didn't work altough the server told me it did.

That's quite byzarre.

> as for the webservices reference, I don't think that applies to
> web-browsers, they could even interpret the 400 as something totally
> different.

Web browser are web clients of web services. There shouldn't
definitely be a difference in status codes among which kind of client
I could get.
There can be a difference in response format (based on Accept or
suffixes) but it's insane to return different status codes based on
the UserAgent.
It reminds of the old day of UA sniffing to render different pages.

My suggestion is to read something about HTTP and REST in general.

Why bend the rules when these are the basic scenarios where HTTP shines?

I can be wrong about the correct status code but returning 200 for an
error situations is asking for troubles and asking for more and more
work for the people who needs to access that web service in the
future: be that a browser, a programming language, a mobile phone or
whatever.

Some web standards are so good because if you do things correctly they
can last and work with clients that are nowhere but in the minds of
future developers.

askel

unread,
Aug 22, 2008, 2:17:57 PM8/22/08
to pylons-discuss
Hello guys,

Do you mind if I chime in? I agree that verify should not use 400 HTTP
status code to indicate failure of verifying variable values. I don't
think that even an failure to parse HTTP request body should be
indicated in such a way as long as there were no failure on HTTP
protocol level. Beside, forcing browser to show its standard error
page for 400 error code when user simply made a mistake entering e-
mail address or phone number is the straightest way to scare your
users to death.

> HTTP is an application protocol (which resides on top of the stack),

IMHO, you are mixing HTTP being an application layer protocol in OSI
model with Pylons/WSGI application protocol that is unique to
particular application and is partially defined by application form
validation rules that are not part of HTTP protocol.

Cheers,

Alex

Cliff Wells

unread,
Aug 22, 2008, 9:09:18 PM8/22/08
to pylons-...@googlegroups.com
On Tue, 2008-08-19 at 11:43 +0200, Lawrence Oluyede wrote:

> I disagree. TCP is the transport protocol (which resides at the
> transport level of the stack).
> HTTP is an application protocol (which resides on top of the stack),
> and I'm pretty sure that
> the creators of HTTP intended to use 400 BAD REQUEST also for such
> cases. As the spec says:
>
> " The request could not be understood by the server due to malformed
> syntax. The client SHOULD NOT repeat the request without
> modifications. "

The "malformed syntax" they refer to is the HTTP protocol syntax (for
example, malformed, missing, or improperly escaped HTTP headers, URLs,
etc).

The key phrase here is "the request could not be understood by the
server".

If a form is missing a field, your server still understood (and could
process) the request, it's your application that refuses the request
because of its own requirements that are completely separate from the
requirements of the HTTP server.

Regards,
Cliff

Jonathan Vanasco

unread,
Aug 22, 2008, 9:43:15 PM8/22/08
to pylons-discuss
I'll admit at the forefront, I'm not a fan of the extreme
'restification' of the web the way the rails evangelists and followers
have pushed for, or the 'restful web services' crowd.

http is the transport protocol. its in the name -- "Hypertext Transfer
Protocol"

throwing a 400 on a form error is confusing to many.

oauth and openid can use it, because they're creating new protocols
based on mapping http stuff. oauth and openid are interpreting the
400x as something specific.

if you want your app to do the same, then fine -- raise a custom
redirect or set the error code yourself. it's not that hard. a large
majority of people want/expect 200 for form errors.

i'm all for allowing people to handle @validate better with more
keywords. i've been pushing for a bunch myself -- I just don't like
the idea of it being the 'new' thing as in 'backwards' compatible. i
think 'forwards compatible' is a better sentiment.

question though -- what if the @validate received the right params,
but there was a db error or some other server error. does that become
another 4xxx code in your system, or are they all lumped into the same
concept. how are those instances translated into the @validate
decorator?

Cliff Wells

unread,
Aug 22, 2008, 10:08:52 PM8/22/08
to pylons-...@googlegroups.com
On Fri, 2008-08-22 at 18:43 -0700, Jonathan Vanasco wrote:
> question though -- what if the @validate received the right params,
> but there was a db error or some other server error. does that become
> another 4xxx code in your system, or are they all lumped into the same
> concept. how are those instances translated into the @validate
> decorator?

Well, much of this problem is due to the same problem so much of the web
has in general: all-around bad planning and poor specifications. It
does seem rather inconsistent that a form shouldn't return a 40x but an
internal server error returns a 50x.

At the end of the day, I suppose it might be acceptable to return a 40x
if you consider POST data as part of the request (at the same level as
GET arguments are). So for instance it seems valid that:

http://domain.com?page=bar

returns a 40x and so a POST to

http://domain.com with a body of page=bar

should too. And once you accept that, it seems reasonable to include
any invalid POST data as a 40x as well. Shrug.

I reserve the right to reverse my position again after I've had another
beer.

Regards,
Cliff

Sok Ann Yap

unread,
Aug 22, 2008, 10:44:20 PM8/22/08
to pylons-...@googlegroups.com
On 8/23/08, Alex wrote:
>
> Beside, forcing browser to show its standard error
> page for 400 error code when user simply made a mistake entering e-
> mail address or phone number is the straightest way to scare your
> users to death.
>

No, on modern browsers, your form validation error page will still be
displayed. I have only tested with Opera and Firefox, but even IE6 can
do it if your page is larger than half a kb [1]

On 8/23/08, Cliff wrote:
>
> If a form is missing a field, your server still understood (and could
> process) the request, it's your application that refuses the request
> because of its own requirements that are completely separate from the
> requirements of the HTTP server.
>

When my app cannot locate a resource, it returns a 404.
When my app cannot recognize the user, it returns a 401.
When my app doesn't like the user, it returns a 403.
When my app thinks a request is broken, it returns a 400.
My app is the HTTP server.

By the way, Django has a rest plugin that is hardcoded to return 400
on form validation failures [2]. Struts has a rest plugin that by
default returns 400 on form validation failures [3]. Pylons already
has a wonderful rest controller. I am merely suggesting to add a
parameter to @validate that is defaulted to 200.

Regards,
Yap

[1] http://support.microsoft.com/kb/q218155/
[2] http://code.google.com/p/django-rest-interface/
[3] http://struts.apache.org/2.x/docs/rest-plugin.html

Ben Bangert

unread,
Aug 23, 2008, 1:51:25 AM8/23/08
to pylons-...@googlegroups.com
On Aug 22, 2008, at 7:44 PM, Sok Ann Yap wrote:

> By the way, Django has a rest plugin that is hardcoded to return 400
> on form validation failures [2]. Struts has a rest plugin that by
> default returns 400 on form validation failures [3]. Pylons already
> has a wonderful rest controller. I am merely suggesting to add a
> parameter to @validate that is defaulted to 200.

Yea..... @validate already has 4 too many options, there's no way it
should have any more, in fact, it shouldn't have as many as it does. ;)

It needs some serious re-working, likely as several decorators, or
options that can be combined in various ways, to avoid having a single
function with 10+ keyword options (eeeeek). There was a proposal
awhile back to split it up, I think that should be revisited. I see no
problem with making this an option for those that want it, we just
need it in a new validate setup.

Cheers,
Ben

Mike Orr

unread,
Aug 23, 2008, 2:20:06 AM8/23/08
to pylons-...@googlegroups.com
400 means general client error, so it's perfectly fine for an invalid
query parameter. 200 tells the client it's OK to bookmark this URL,
and messes up your access log statistics. 500 makes it look like the
server is broken. Often these malformed URLs are dumb spiders or
attacks, and 400 tells them to go to hell. On my sites I've seen URLs
without required query parameters (indicating they didn't go through
my links), or with a parameter set to an external URL (spam attempt).
It's an easy one-liner to do:

abort(400, "required query param 'foo' missing")

On Fri, Aug 22, 2008 at 10:51 PM, Ben Bangert <b...@groovie.org> wrote:
> @validate already has 4 too many options, there's no way it should
> have any more, in fact, it shouldn't have as many as it does. ;)
>
> It needs some serious re-working, likely as several decorators, or options
> that can be combined in various ways, to avoid having a single function with
> 10+ keyword options (eeeeek). There was a proposal awhile back to split it
> up, I think that should be revisited. I see no problem with making this an
> option for those that want it, we just need it in a new validate setup.

http://pylonshq.com/project/pylonshq/ticket/405

I want to work on this when I have time because there are so many
cases where @validate is too monolithic. (E.g., need a database
record to validate against, don't need a whole validator class.) In
the meantime there's code in the ticket if somebody wants to try it
out.


--
Mike Orr <slugg...@gmail.com>

Mike Orr

unread,
Aug 23, 2008, 2:58:45 AM8/23/08
to pylons-...@googlegroups.com
On Fri, Aug 22, 2008 at 6:43 PM, Jonathan Vanasco <jona...@findmeon.com> wrote:
>
> I'll admit at the forefront, I'm not a fan of the extreme
> 'restification' of the web the way the rails evangelists and followers
> have pushed for, or the 'restful web services' crowd.

Remember that REST is just a vague concept like MVC. It just means to
use a meaningful URL structure. It' doesn't say what those URLs
should be, which HTTP methods to use, or what to name your controller
actions. map.resource/ATOM is a particular implementation of REST,
not REST itself.

map.resource makes a lot of sense for things that will be aggregated
or called by programs. It makes some sense for things that will be
called only through an interactive web browser, but there are
tradeoffs. Using pseudo-PUT and DELETE in web browsers is
questionable. Having a "/foos/1/edit" that PUTs to "/foos/1" is
funny; why not post to the same URL as the form? Why is there no
delete confirmation form ("/foos/1/ask-delete", which I add to every
resource). One of the things I want to add to Routes 2 is a
simplified add/modify/delete structure for cases where map.resource is
overkill. (And one that enables only specific actions; e.g., no
delete or no index.)

The other problem is nested resources.
"/incidents/123/entries/456/attachments/789/edit" is really long, and
fails to show the close relationship of an item to its id. With
non-numeric IDs, you may not even be able to tell which are items and
which are IDs. In my old site I had /123/456/edit, which made it
easier to see the whole URL in the location bar and to type it by
hand. But I wanted to do it the "right" way in Pylons, and nested
resources were too precarious and undocumented to be trusted, so I
ended up flattening the resources to /incidents/123 and /entries/456.
(All entry IDs were unique, so the latter worked.)

--
Mike Orr <slugg...@gmail.com>

Wyatt Baldwin

unread,
Aug 23, 2008, 1:41:23 PM8/23/08
to pylons-discuss
On Aug 22, 11:58 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
> On Fri, Aug 22, 2008 at 6:43 PM, Jonathan Vanasco <jonat...@findmeon.com> wrote:
>
> > I'll admit at the forefront, I'm not a fan of  the extreme
> > 'restification' of the web the way the rails evangelists and followers
> > have pushed for, or the 'restful web services' crowd.
>
> Remember that REST is just a vague concept like MVC.  It just means to
> use a meaningful URL structure.  It' doesn't say what those URLs
> should be, which HTTP methods to use, or what to name your controller
> actions.  map.resource/ATOM is a particular implementation of REST,
> not REST itself.
>
> map.resource makes a lot of sense for things that will be aggregated
> or called by programs.  It makes some sense for things that will be
> called only through an interactive web browser, but there are
> tradeoffs.  Using pseudo-PUT and DELETE in web browsers is
> questionable.  Having a "/foos/1/edit" that PUTs to "/foos/1" is
> funny; why not post to the same URL as the form?  Why is there no
> delete confirmation form ("/foos/1/ask-delete", which I add to every
> resource).

>  One of the things I want to add to Routes 2 is a
> simplified add/modify/delete structure for cases where map.resource is
> overkill.  (And one that enables only specific actions; e.g., no
> delete or no index.)

Word up to that. I've written two versions of functions that do this
in two different projects. They're probably not ready for general
production use, but I'll share the code if you are (or anyone else is)
interested.


> The other problem is nested resources.
> "/incidents/123/entries/456/attachments/789/edit" is really long, and
> fails to show the close relationship of an item to its id.  With
> non-numeric IDs, you may not even be able to tell which are items and
> which are IDs.  In my old site I had /123/456/edit, which made it
> easier to see the whole URL in the location bar and to type it by
> hand.  But I wanted to do it the "right" way in Pylons, and nested
> resources were too precarious and undocumented to be trusted, so I
> ended up flattening the resources to /incidents/123 and  /entries/456.
>  (All entry IDs were unique, so the latter worked.)
>
> --
> Mike Orr <sluggos...@gmail.com>

Jonathan Vanasco

unread,
Aug 24, 2008, 6:47:39 PM8/24/08
to pylons-discuss
On Aug 23, 2:20 am, "Mike Orr" <sluggos...@gmail.com> wrote:


> I want to work on this when I have time because there are so many
> cases where @validate is too monolithic.  (E.g., need a database
> record to validate against, don't need a whole validator class.)  In
> the meantime there's code in the ticket if somebody wants to try it
> out.


its very buggy code that was written before i understood how
form_errors works
i think on my next pass, i'd make sure that there's alawys a
form_errors dict in c.... it would just be empty if unset.

Ian Bicking

unread,
Aug 28, 2008, 5:21:49 PM8/28/08
to pylons-...@googlegroups.com
Sok Ann Yap wrote:
> Currently, the validate decorator always return 200 OK when validation
> fails. I think 400 Bad Request is more appropriate here, so that it
> will be easier for non-browser application to interact with the pylons
> app. Maybe we can add a parameter to @validate that is defaulted to
> 200, to make it backward compatible.

Well, the thread is old and kind of closed, but just for the record I
think a 400 Bad Request code is entirely reasonable for this case, and a
good use of that response code, with little ill effect (assuming, as was
noted, that you respond with a large enough body to avoid the IE error
page).

--
Ian Bicking : ia...@colorstudy.com : http://blog.ianbicking.org

Reply all
Reply to author
Forward
0 new messages