We were babbling on IRC, as we tend to do. I mumbled about this a couple of days ago, and then Double-A Porter got on his bullhorn about StripesStuff.
I want to explore adding a more formal REST capability to Stripes. I think that there is great value is adding better "full bodied" REST Support to an Action framework like Stripes. If you cruise around the Intratubes, you'll find that we have Action Frameworks, but we also have REST Specific frameworks as well. Turns out the Action frameworks don't actually support REST as well as they could, and REST frameworks don't support classic web apps very well, if at all. Now, some may say "WTH? What's so hard about REST? It's just HTTP, eh?" Yes, it is just HTTP. Which is why it's kind of silly to need two "HTTP" Frameworks to make writing this server side logic. "But if REST is just HTTP, why can't we just use Stripes out of the box?" Well, first it doesn't come in a box -- you have to download it. But, be that as it may, Stripes, like most every other Action Framework, actually supports only a subset of HTTP. For example, we had the post earlier about the other HTTP verbs and how, save for GET and POST, Stripes pretty much just shows them the door. That's Bad(tm). See, the REST wonks want to use all of those other verbs: HEAD, PUT, DELETE, etc. In fact, some want to make their own as well (for example, WebDAV creates its own HTTP verbs). This is fully within the HTTP spec, making this stuff up as you go. Now, while you Cro-Magnon web page grognards from the "when I was a kid, all we had was GET, 14K modems, and Perl" school of web programming are happy with the status-quo. REST aficionados, umm, ain't. Fortunately, it should not be a real leap to bring Stripes in to the 21st century, and be a Good Citizen with the rest of the HTTP protocol. Ideally, this can all be done in Stripes Stuff with interceptors, so as not to need to change Stripes core and offend Tim and his "GET OFF MY LAWN" ways. I think the primary thing is to be able to expose the HTTP verb as a first class part of the binding and event mechanism. The requirements are: + Stripes works as it always has -- this is an "opt in" system. So, breaking classic Stripes is off the table. + First class handling of the Standard HTTP verbs: GET, PUT, POST, DELETE, HEAD, OPTIONS. TRACE and CONNECT appears to be server level Verbs, so we'll punt on those. + Ability to support other verbs. This means, basically, being able to bind to a String. + Better support, perhaps through utility methods for content negotiation, HTTP headers, and response codes. Response codes are a Big Deal to REST folks, so they should be easy. + Easy return of ValidationErrors in some format besides HTML (i.e. XML or JSON) + Ideally, binding to other data types beside multipart form requests, notably XML and JSON, though this is at the bottom of the list for a reason. In REST, it's important that the same URL do different things depending on the verb. Right now, Stripes conflates GET and POST to mean the same thing. To the REST cognoscenti, the two are quite, quite, different. So, we need to be able to readily handle differentiating those two kinds of requests, even tho the URL is identical. There's two ways to do that. One is annotating a method with @Rest, or @Http or something, and then using a configuration by convention meme base on the name of the event. For example: // Default rest binding public class PersonActionBean { @Http public Resolution post() { ... } @Http public Resolution get() { ... } @Http public Resolution delete() { ... } @Http {method="MYHTTPVERB"} public Resolution myHttpVerb() { ... } } If an event is passed, we could do: public class PersonActionBean { // For event name "view" @Http public Resolution postView() { ... } // should this be viewPost? @Http public Resolution getView() { ... } @Http public Resolution deleteView() { ... } @HandlesEvent("view") // stock stripes annotation @Http {customMethod="MYHTTPVERB"} public Resolution myHttpVerbForViewEvent() { ... } } If we punt on CbC, and be explicit we can do: @Http(method={HttpVerb.DELETE, HttpVerb.PUT}, customMethod= {"MYDELETE", "MYPUT"}, eventName="shazam", default=true) where method = The HTTP verbs that this event would bind too. customMethod = Custom HTTP verbs to bind to eventName = the name of the event to bind too And stock @DefaultHandler would be used to tell us that it's the default for that specified methods. By default, any event that isn't annotated would be considered as method={HttpVerb.POST, HttpVerb.GET}, i.e. both, like Stripes is now. Does anyone like or dislike either of these techniques for binding events? For content negotiation, I think just some utility methods can be used to break up and make the content-types more available to the user. I don't see a need to dispatch on content type (though that could be interesting as well, I think it's something that could also be layered in later). For the Headers and ResultCodes, that can probably be handled with a couple of new Resolution types, I don't recall how stripes handles result codes right off the top of my head. We saw the issue that Freddy had with having to extend ForwardResolution to add his Success header, a customer resolution that lets us tack on headers would be trivial to do. As for returning errors in a different format than HTML, that could also be done, I think through a custom resolution, JSONErrorsResolution, or XMLErrorResolution, and the dispatch code could (somehow) know which one to you, either by configuration or, ideally, content negotiation. For now, I'll punt on potentially binding other data type for input besides mutlpart form requests. I think there's value here, as many REST services are POX services, as well as multipart, and Ajaxy types like chatting in JSON. The basic thought was that the process would "flatten" the in coming XML or JSON into, effectively, multipart parameters, and then let Stripes do the rest of the work. Also, we make available, perhaps, the DOM of the XML if the action has a Document field. And, perhaps, something appropriate for JSON (I don't know much about JSON, so I can't say what this would be, heaps of bags of maps of maps maybe). Obviously, if you send stuff that the standard Stripes binding can't do, then, well,it doesn't work. Don't do that. Be nice to Stripes, it'll be nice to you. Save for the potential binding of incoming data, you can see that this should not be a horrible amount of work. And I'm not suggesting anyone take it on, or that the Stripes guys do it. But I would like to have your thoughts about the approach, which you like better, and any suggestions that y'all might have. Regard, Will Hartung ------------------------------------------------------------------------- Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! Studies have shown that voting for your favorite open source project, along with a healthy diet, reduces your potential for chronic lameness and boredom. Vote Now at http://www.sourceforge.net/community/cca08 _______________________________________________ Stripes-users mailing list Stripes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/stripes-users