views:

728

answers:

4

Even if I offer alternatives to PUT and DELETE (c.f. "Low REST"), how can I provide user-friendly form validation for users who access my web service from the browser, while still exposing RESTful URIs? The form validation problem (described below) is my current quandry, but the broader question I want to ask is: if I go down the path of trying to provide both a RESTful public interface and a non-javascript HTML interface, is it going to make life easier or harder? Do they play together at all?

In theory, it should be merely a matter of varying the output format. A machine can query the URL "/people", and get a list of people in XML. A human user can point their browser at the same URL, and get a pretty HTML response instead. (I'm using the URL examples from the microformats wiki, which seem fairly reasonable).

Creating a new person resource is done with a POST request to the "/people" URL. To achieve this, the human user can first visit "/people/new", which returns a static HTML form for creating the resource. The form has method=POST and action="/people". That will work fine if the user's input is valid, but what if we do validation on the server side and discover an error? The friendly thing would be to return the form, populated with the data the user just entered, plus an error message so that they can fix the problem and resubmit. But we can't return that output directly from a POST to "/people" or it breaks our URL system, and if we redirect the user back to the "/people/new" form then there is no way to report the error and repopulate the form (unless we store the data to session state, which would be even less RESTful).

With javascript, things would be much easier. Just do the POST in the background, and if it fails then display the error at the top of the form. But I want the app to degrade gracefully when javascript support isn't available. At the moment, I'm led to conclude that a non-trivial web app cannot implement an HTML interface without javascript, and use a conventional RESTful URL scheme (such as that described on the microformats wiki). If I'm wrong, please tell me so!

Related questions on Stack Overflow (neither of which deal with form validation):

  • #1246061 How to send HTML form RESTfully?
  • #46004 How do you implement resource “edit” forms in a RESTful way?
A: 

Why not use AJAX to do the work on the client side and if javascript is disabled then design the html so that the conventional POST would work.

Monis Iqbal
Hmm, I could get it to *work*, probably by having the HTML form post to "/people/new". But that means using non-RESTful URLS, again leading me to the conclusion that vanilla HTML forms are simply not compatible with the REST philosophy.
Todd Owen
@Todd "RESTful URLs" is a nonexistent concept. REST specifies nothing about URIs except that they must be opaque.
Wahnfrieden
I posted a similar question about how HTML forms fit into REST. Check it out
Wahnfrieden
IMO the actual HTML form interface is separate from REST. The form should be able to be built from the knowledge of the REST API, not from interacting with the API.
Wahnfrieden
+4  A: 

you could have the html form post directly to /people/new. If the validation fails, rerender the edit form with the appropriate information. If it succeeds, forward the user to the new URL. This would be consistent with the REST architecture as I understand it.

I saw you comment to Monis Iqbal, and I have to admit I don't know what you mean by "non-RESTful URLS". The only thing the REST architecture asks from a URL is that it be opaque, and that it be uniquely paired to a resource. REST doesn't care what it looks like, what's in it, how slashes or used, how many are used, or anything like that. The visible design of the URL is up to you and REST has no bearing.

Breton
By "non-RESTful" I meant that it doesn't fit the suggestions outlined on http//microformats.org/wiki/rest/urls, which recommends that a new resource be created by a POST to "/people". I see your point though -- my interface can just as easily be: GET "/people/new" = blank form, POST "/people/new" = create resource.
Todd Owen
Oh yeah, those reccomendations. I remember when they invented them. Notice how it says at the top that ruby on rails used to use ;edit and ;new ? That was my dumb idea, because edit, and new didn't seem like to me lik *seperate* resources from /people, just a different way to render the same resource. so I found the semicolon could be used to indicate that, instead of the child relationship / implies. ; broke safari though, so flltt.
Breton
In any case, you could also model it so that POST /people renders your "new" form but with alerts about what went wrong.
Breton
That way you're following the reccomendations, and your api can be used by those things it says are compatible with that form.
Breton
in retrospect I wish I'd suggested . instead. Then you'd still have the distinction, but you wouldn't end up breaking safari.
Breton
@Breton your code got censored in the comment
Wahnfrieden
looks fine to me. I guess it's potentially confusing because I refer to a lot of symbols without quoting them.
Breton
Ah sorry. @Todd FYI REST has nothing to do with proper usage of HTTP verbs, and there's no such thing as "RESTful URLs" despite what it says in your link. REST doesn't care what your URIs look like.
Wahnfrieden
A: 

Thanks for the responses. They have freed my mind a bit, and so in response to my own question I would like to propose an alternative set of RESTful URL conventions which actually embrace the two methods (GET and POST) of the non-AJAX world, instead of trying to work around them.

Edit: As commenters have pointed out, these "conventions" should not be part of the RESTful API itself. On the other hand, internal conventions are useful because they make the server-side implementation more consistent and hence easier for developers to understand and maintain. RESTful clients, however, should treat the URLs as opaque, and always obtain them as hyperlinks, never by constructing URLs themselves.

GET /people
    return a list of all records
GET /people/new
    return a form for adding a new record
POST /people/new
    create a new record
    (for an HTML client, return the form again if the input is invalid, otherwise redirect to the new resource)
GET /people/1
    return the first record
GET /people/1/edit
    return a form for editing the first record
POST /people/1/edit
    update the first record
GET /people/1/delete
    return a form for deleting the record
    (may be simply a confirmation - are you sure you want to delete?)
POST /people/1/delete
    delete the record

There is a pattern here: GET on a resource, e.g. "/people/1", returns the record itself. GET on resource+operation returns an HTML form, e.g. "/people/1/edit". POST on resource+operation actually executes the operation.

Perhaps this is not quite so elegant as using additional HTTP verbs (PUT and DELETE), but these URLs should work well with vanilla HTML forms. They should also be pretty self-explanatory to a human user...I'm a believer in the idea that "the URL is part of the UI" for users accessing the web server via a browser.

P.S. Let me explain how I would do the deletes. The "/people/1" view will have a link to "/people/1/delete", with an onclick javascript handler. With javascript enabled, the click is intercepted and a confirmation box presented to the user. If they confirm the delete, a POST is sent, deleting the record immediately. But if javascript is disabled, clicking the link will instead send a GET request, which returns a delete confirmation form from the server, and that form sends the POST to perform the delete. Thus, javascript improves the user experience (faster response), but without it the website degrades gracefully.

Todd Owen
Do you really want to create a RESTful interface? If so, stop trying create URL conventions. Beyond that, I'm not seeing anything here that you cannot already do with AtomPub. Why re-invent the wheel?
Darrel Miller
Defining URI conventions as part of your API means that your API is RPC. URIs must be discoverable via hypertext, starting with a single entry-point URI. See: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Wahnfrieden
Thank you, I will remember that. In which case, the URLs I listed are not part of the API, merely an implementation decision...to which a RESTful client should pay no attention. They just happen to be fairly convenient to implement (in Struts 2, at least, which is that framework that I'm using), and also compatible with vanilla HTML forms. [Answer edited to clarify this.]
Todd Owen
@Todd that's reasonable, there's nothing *wrong* with pretty URIs. Just make sure they're discoverable through hypertext.
Wahnfrieden
+2  A: 

Why do you want to create a second "API" using XML?

Your HTML contains the data your user needs to see. HTML is relatively easy to parse. The class attribute can be used to add semantics as microformats do. Your HTML contains forms and links to be able to access all of the functionality of your application.

Why would you create another interface that delivers completely semantic free application/xml that will likely contain no hypermedia links so that you now have to hard code urls into your client, creating nasty coupling?

If you can get your application working using HTML in a web browser without needing to store session state, then you already have a RESTful API. Don't kill yourself trying to design a bunch of URLs that corresponds to someone's idea of a standard.

Here is a quote from Roy Fielding,

A REST API must not define fixed resource names or hierarchies

I know this flies in the face of probably almost every example of REST that you have seen but that is because they are all wrong. I know I am starting to sound like a religious zealot, but it kills me to see people struggling to design RESTful API's when they are starting off on completely the wrong foot.

Listen to Breton when he says "REST doesn't care what [the url] looks like" and @Wahnfrieden will be along soon to tell you the same thing. That microformats page is horrible advice for someone trying to do REST. I'm not saying it is horrible advice for someone creating some other kind of HTTP API, just not a RESTful one.

Darrel Miller
Thanks for the informative link. Actually I don't need the XML interface right away, but I see it as a good test of a clean application architecture (specifically, separation of presentation from business logic). If the application can emit XML in addition to HTML, with minimal effort for the developer, then it should be easy to emit *any* output format that might be required in the future.
Todd Owen
HTML is quite easily made into a subset of XML anyway.
Wahnfrieden
@Todd, this comes back to my opinion that RESTful interfaces are for exposing content to a "user-agent" not business data to consumer applications. That's what web services are for. I see RESTful interfaces and Web Services as solving two different problems.
Darrel Miller