1

I'm loading a "Create User" form into a modal dialog as a partial view. Within that view, I'm using the MVC helper Ajax.BeginForm, specifying InsertionMode.ReplaceWith and an UpdateTargetId set to the form itself, so the form can be submitted and it will return an updated version of itself and replace itself if more information is needed. Basically, the AJAX request is expected to return HTML.

How should I communicate other results of such an AJAX request, such as when the operation is complete and there is no HTML to return (e.g. the user was successfully created, so the modal dialog needs to be closed)?

Could I use HTTP Status Codes or Content Type headers? I'm looking for the cleanest way to accomplish this while maintaining compatibility with the existing Ajax.BeginForm method which uses Microsoft's unobtrusive AJAX. Perhaps I'd need to specify an OnComplete handler in the AjaxOptions, check the status code or content type, then cancel the default "ReplaceWith" behavior if the operation has completed and has no HTML to return.

I'm thinking along the same lines as this comment from another post: "It doesn't seem practical to test the response by examining the HTML content for an error message rather than just testing the response code." Using Http Status Codes During Form Validation

Community
  • 1
  • 1
Triynko
  • 18,766
  • 21
  • 107
  • 173

2 Answers2

0

Using http status codes is problematic. Consider an AJAX-based search engine. User punches in some random junk, which have no results. The server can signal back the "no results" in two ways:

404 - "requested url not found". That's an HTTP-level error, which MUST be interpreted as "the search engine script is not there". That is exactly the WRONG thing to do - the script exists, it ran, it simply found no results. But now the browser is left thinking that the search URL is bad.

200 - OK, and return search status information in the result body. e.g. some json: {"status":"ok","results":[]}. This is the PROPER thing to do. The search script exists, it ran, it successfully queried the DB, it simply has no results to return to the user.

In real world terms, it's the equivalent of your spouse telling you to go to the store and buy Random Item X. You drive to the store, the store's there, it's open, but it's simply out of stock. In this case. "404" - store does not exist. "200"+json - store exists, but has no stock.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • 2
    Sorry, but that's incorrect. 404 means the requested *resource* was not found. It has nothing to do with the URL other than the URL being the indication of what resource is being requested. Further, query strings are part of the URL and thus, differentiate it. A request for `google.com?q=Foo` is a completely different resource than `google.com?q=Bar`. If no results exist for "Foo" then it is 100% appropriate to return 404, and has no bearing on what the browser would expect to see from a search fro "Bar". – Chris Pratt Oct 06 '15 at 19:18
  • 1
    To clarify, a search engine like Google would never return a 404 in such an instance, because that would make for a bad UI. However, in a situation like an API, you *would* see a 404, as it would be highly appropriate and there's no UI to concern with. That is a choice made by the website, though, and doesn't have anything to do with the actual meanings of the HTTP status code. – Chris Pratt Oct 06 '15 at 19:20
  • Consider this. The standard defines status codes that seem to fit the bill perfectly here, such as 201 (Created) and... "205 (Reset Content): The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action." http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html – Triynko Oct 06 '15 at 19:50
  • @ChrisPratt: and that's where the problem is. what is the resource being fetched? The requested item, or the script HANDLING the search? if it was something like a DELETE command, then a 404-not found is entirely appropriate. but on things like searches/api requests, using the http layer to signify problems with the api is just... wrong. – Marc B Oct 06 '15 at 19:52
  • Obviously I could return JSON, but in this case the response is typically HTML. The question is whether I should switch between the two by specifying a different content type (which will be checked client-side), or simply check the status code, which is already returned to the handlers. If it's a 200, I would simply show the HTML, and if it's a 201 "Created", I would close the modal dialog. – Triynko Oct 06 '15 at 19:54
  • 1
    The resource is the resource, in this case search results for a particular term. If no results exist for that term, then it's a 404, plain and simple. HTTP doesn't know or *care* whether there's some actor on the other end making that determination or not (the "script"). – Chris Pratt Oct 06 '15 at 19:54
  • The way I see it, people simply have never been using the HTTP standard the way it's supposed to be used. They've always used it in the most simplest way, basically pass or fail, while it actually includes a robust set of status codes. If I were requesting a resource and got a 200 (OK), that's fine. But there's also POST operations, for which statuses of 201 (Created) make sense. The resource, in this case, is actually the posting of an object, which does not return anything. – Triynko Oct 06 '15 at 19:56
  • I think we're underutilized status codes, assuming they're something only the browser should deal with. In the age of AJAX requests, where the application is dealing directly with HTTP responses, I think we need to use status codes better. For example, I already use them to look for a 501 or 502 "Unauthorized" to trigger a "location.reload", which will kick a user back to the login screen when an AJAX request fails due to user session expiring. – Triynko Oct 06 '15 at 19:58
  • @Triynko: that's basically true. There are a range of very specific response codes. However, not all of those have existed since HTTP was first created. Some were added in HTTP 1.1 and more yet have been added in HTTP 2.0. There's also situations where a particular code would never apply. For a `create` endpoint, 404 would never be returned, although other error codes might be. – Chris Pratt Oct 06 '15 at 19:59
  • Right, but I'm just entertaining the idea that for AJAX requests, setting and utilizing http status codes is an acceptable (or even best) practice. When you're dealing with in-page requests, it's basically more like an API than a page request. – Triynko Oct 06 '15 at 20:08
  • I think where it may run into problems is that, for example, jQuery already performs heavy processing on the status codes. For example, within the "ajax" function definition, I see lines like `isSuccess = status >= 200 && status < 300 || status === 304;` and `if ( status === 204 || s.type === "HEAD" ) {statusText = "nocontent"; } else if ( status === 304 ) {statusText = "notmodified";`. So maybe it is cleaner to just let it return 200 (OK), and process application-level results found in the returned JSON content. Then again, as long as I have a code in the 200 range, this is just extra info. – Triynko Oct 06 '15 at 20:17
  • 1
    Right. See my comment below my answer. As long as you can use *reliably*. It's very possible it's a good code that you should totally use, but if the library you're using doesn't understand it, or the browser does something to mask it, or the server doesn't send it out properly, or whatever, then it's no longer workable. Just do some testing and if everything works, then go for it. While a true API should always return a specific an "correct" code, it's really not so mission critical for your particular application here. At the end of the day, I'd say do what works the best and is easiest. – Chris Pratt Oct 06 '15 at 20:24
  • Agreed. It seems that an application needs to clearly define what "resource" is associated with a particular URL. E.g. if the resource is conceptualized as "a square of any color", then a 404 returned by either "square?color=blue" or "square" could both be interpreted as the square script is missing. However, if you conceptualize the resource as "a square of a particular color", then "square?color=blue" is distinct from "square", and while a 404 from the more specific one could indicate that particular square color is missing, a 404 from "square" itself could indicate the script is missing. – Triynko Oct 06 '15 at 20:40
0

Yes, response codes should always indicate the status. If everything is good you should return 200, regardless. However, response code alone is not helpful to you in this situation.

For example, whether there's new HTML to be loaded, or the modal simply needs to be closed, the response code would be 200 in either case. If you need variability in the response, then you need to stop using the Ajax controls.

In general, I discourage everyone from using any of the Ajax controls. What slight gains you may get in ease, you lose drastically in visibility and control over what's happening. Almost invariably when people use these controls, they find their way here or some other site asking for help because something or another isn't working.

If you implement your own AJAX, then you can return a JSON object which will give you infinitely more flexibility. You can encode whatever statuses you like and include HTML that should be rendered, if you like. Then, you can inspect that object in your AJAX callback and react appropriately, instead of relying on Microsoft to decide what should be done.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • This isn't the case at all. The Ajax.BeginForm offers out-of-the box simplicity. It's event handlers mirror the jQuery API exactly, so I have just as much control over it as I would if I were to call jQuery.ajax directly. The *only* limitation would be that with Ajax.BeginForm, the On* handlers must be specified as globally reachable function names, as opposed to function references. Having said that, I'm asking whether I should set a response code other than 200 (OK) to indicate the result of an operation. For example, there is 201 (Created). – Triynko Oct 06 '15 at 19:49
  • In fact, there appears to be another response code defined in the standard for EXACTLY my situation: "205 (Reset Content) The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action." – Triynko Oct 06 '15 at 19:49
  • You're basically right, using a JSON object consistently makes it easier. However, I can't get past the idea that the protocol already includes a content type and status that we're basically just ignoring. – Triynko Oct 06 '15 at 20:07
  • 1
    If you want to go that route, that's fine. I didn't actually know of 205, previously, but it's not like I've memorized the full list so I can apply whichever is most appropriate at any given moment either. (Another reason most likely for some under-utilization: the human brain just can't feign enough interest to keep all the codes in wet storage). Anyways, if you found a code that works and you can use it reliably, then I think that's a perfectly acceptable way forward. – Chris Pratt Oct 06 '15 at 20:18