Hi folks,
Been a while... Getting back to geek life, little by little :-)
I'm not convinced by this REST stuff. To be honest, I'm amongst the
ones who think that when it comes to RPC, no matter what HTTP method
is used, what you need is simply an endpoint that responds to an HTTP
request. Then, request parameters are enough to decide what to do. To
be honest I don't even understand the buzz that has been created
around this HTTP method stuff lately... People trying to build new
middleware over HTTP again ? Erf, deja vu :P
But sure, the idea of exposing action beans as programatic services,
available to "fat" clients, is a good one. And there are very simple
and effective ways to do it already... :)
We already have a Stripes extension in Woko that allows instant RPC
enabling of a Stripes action bean.
Example bean :
class MyAction ... {
public Resolution doIt() {
...
return new RedirectResolution(...);
}
}
The doIt() event returns a redirect, thus making it hardly usable from
a fat client, or a javascript in the client browser. Moreover, if
validation errors occur, or an exception is thrown, then HTML is
returned in the response, and again is hardly usable by a fat client.
Now what if you wanna enable this event for fat clients ? Well, easy,
just annotate the event method, and define another one that handles
streaming of the result in the format you want (Woko supports JSON and
XML ootb, but you could even write your own format) :
class MyAction ... {
@FatClientEvent(method="doItFat")
public Resolution doIt() { ... }
public Resolution doItFat(Resolution originalResolution) {
String myJson = ... ;
return new StreamingResolution("text/plain", myJson);
}
}
Thanks to a specific interceptor, and using a specific request
parameter, you can now invoke this action bean from the browser, the
regular HTML way :
http://.../myapp/my.action?doIt=true&... -> returns HTTP redirect
Or from any client that is able to send HTTP requests and understands
your format :
http://.../myapp/my.action?doIt=true&fatClient=true&... -> return JSON
Of course, the interceptor also handles exceptions and validation
errors (streamed back as JSON or XML).
The good thing with this approach IMHO is that you reuse the existing
logic, as the real event is actually invoked, only the returned
resolution is discarded for another, fat client enabled one. You
expose functionnality of your application to third party apps without
touching the human interface (HTML and flows).
This "trick" is very simple and consistent, and allows to RPC enable
any existing action bean at a very low cost, without any impact on the
existing logic inside your action bean's event methods.
And really, you don't need any "verb" at all ! GET, POST, PUT,
DELETE... this is just useless : you already have events :-P
We have RPC-enabled all CRUD (and full text search) features of Woko
with this technique : you can actually do everything you do by
clicking in the browser with a fat client.
http://woko.wiki.sourceforge.net/AjaxBackend
http://woko.wiki.sourceforge.net/AjaxExamples
The RPC layer was added after he whole web stuff was working, and
again it was not intrusive by any mean. It broke no existing web page,
and didn't even require any refactor of the existing code...
Ok, I might be drifting OT a little bit : your post was about the use
of HTTP method (verbs) in the context of RPC with Stripes. But again,
I think this verb stuff is straight overengineering. I mean, why would
you need this ? Is there a good explanation of the advantages of this
approach somewhere ??? I've never seen such stuff, and it's never been
a problem to me. RPC over HTTP is clearly suckish, but hey, that's
pretty easy to implement and you don't really need all this overhead
IMHO...
Send stuff, get stuff back. As simple as this :)
My 0.02
Fat Rémi
On Wed, Jul 9, 2008 at 6:36 AM, Will Hartung <[EMAIL PROTECTED]> wrote:
> 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
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/stripes-users
>
-------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-users