struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dusty <>
Subject Re: RESTful form tags
Date Sat, 05 Jul 2008 18:50:27 GMT

Ok, I have thought about it.  ;-)

For each resource there are a number of REST paths that are
created/needed/whatever.  Each path has a route name and two parameters
(method and id).  

GET /orders              orders :method = get (default)
GET /orders/new        orders_new
POST /orders             orders :method = post
GET /orders/1            order :method = get (default) , :id = 1
GET /orders/1/edit     order_edit :method = get, :id = 1
PUT /orders/1            order :method = put , :id = 1
DELETE /orders/1       order :method = delete, :id =1

In today's world I usually create a small "Routes" section at the top of the
page and use <s:url id=xxx/> to create my urls that I will reference later
in the page.   The new tags would have some new parameters:

* route: the route name based on the convention above
* method: the http method to use (default: GET)
* id: the id to append to particular routes (default: %{id})

<s:url route="orders_path"/>  = GET /orders 
<s:url route="order_path"/>  = GET /orders/%{id}

What about PUT, DELETE and POST.  Well when you selecting a named route for
a link for instance and you are using something other than GET, then the
generated link should actually create a form with a hidden _method field and
post to the server (with id if appropriate).  It should also be smart enough
to know that when I am in a s:form and using route="xxx" and method = "put"
that i need to add a hidden field to my form.  

<s:form route="order_path" method="put"/> = <form action="/orders/%{id}"
method="POST"><input type="hidden" name="_method" value="PUT"/></form>

s:url is probably not as useful because what I really want to do is either
generate a &lt;a/&gt; tag or a &lt;form/&gt; and a &lt;a/&gt; tag
submits the form.  The current a tag has a lot of "stuff" and so I am not
sure if this is a new <s:restA/> or an adaptation of the existing A tag.  I
think the idea of separating the s:url and s:a because of parameters is not
a great idea.  Instead we should use an OGNL hash for any "extra" parameters
you want in the link.  Obviously for a form you just include the fields....

Here is a use case....

I want to iterate over orders and generate an "Update Status to Complete
link" as a column in the table.

<s:iterator value="model"/>
     <td><s:a route="order_path" method="put" id="id"

<td><form action="/orders/[id for model in loop]" method="post"
id="something generated i can reuse in my link"><input type="hidden"
name="_method" value="PUT"/><input type="hidden" name="status"
value="complete"/></form>&lt;a href=javascript:document.forms['reused
id'].submit();return false&gt;Complete&lt;/a&gt;</td>   

.... or something better ;-)

Some key points:

* s:a and s:form are the priority but s:url and s:action should have the
same behavior if they are going to still be around.

* Any method other than GET generates a form (if not already a form) and

* Tags parse the route name for one of the four names (models, model,
models_new, model_edit) to figure out the base url.  This is where
convention really makes a difference because if you misspell your route name
then it will break.  (Of course you could always create the urls by hand
like we do today....but that is the benefit of convention)

* the tag parameters should evaluate so you can insert the id of something
in the ValueStack or you can even build your route name based on the
valueStack.  (This gets to some of the struts2 syntax "sugar")
   ** route: "orders" = string orders "%{orders}" orders value on the stack. 
   ** id: "id"  = id value on the stack "%{'id'}" string id.  Yes/No?
   ** method: "get" string get "%{get}" get value on the stack. Yes/No?

* Using GET with a params hash will just append to the querystring so: <s:a
route="order_path" id="id" params="#{'status':'complete'}/> creates

* Custom actions are just appended to the route name.  So if you had an
action called deleteConfirm then you would have the route <s:a
route="order_deleteConfirm"/> which is /orders/%{id}/deleteConfirm and <s:a
route="orders_deleteConfirm"/> which is /orders?action=deleteConfirm.  (the
second url is funny because I don't think the ActionMapper can tell the
difference between /orders/1 and orders/deleteConfirm and not think that
deleteConfirm is an order id.)

That is a start and I think its a pretty straight forward implementation.  I
am sure it can be refined and improved.  I am not so sure about how to setup
"evaluation" of tag parameters against the stack.  This whole brain dump
spawned another idea, separate from REST but related, Named Routes.

Named Routes are configured in struts.xml and allow the developer to create
custom urls.  So in struts.xml I enter:

<route name="secret_back_door" path="/secret/:key/:function"
controller="admin" action="index" methods="GET"/>

This should do a few things:
1. When it sees /secret/DE2134123DF123412312321/report it will call the
index() method of the class AdminController and pass in

2. When I write <s:a route="secret_back_door"
params="#{'key':'DE2134123DF123412312321','function':'report'}/> I get

3. If I try to use PUT, POST or DELETE for this named route its an error. 
If I wanted it to respond to more methods then I would add them in
struts.xml methods="GET,POST"

I am not as sure how to implement this, but I know how to use it in my head. 

dusty wrote:
> That is a very good question Don.  I am going to have to actually think
> about that if you don't mind...
> Don Brown-2 wrote:
>> On Sun, Jun 22, 2008 at 1:46 PM, dusty <> wrote:
>>> In my UI I have things like <s:url/> and <s:form/> and <s:action/>
>>> are
>>> going to need to address resources.  The routing system should make it
>>> easy
>>> for me to both recognize incoming urls and to define rules for outbound
>>> url
>>> html.  Is the answer to create a custom tag library for <s:form/> that
>>> hides
>>> the url details? or use a <s:url/> and reference that in <s:form>.
>>> think
>>> making the action param evaluate is moving in the wrong direction,
>>> making it
>>> even more forced.  A centralized REST routing system would be better so
>>> that
>>> we can just reference it when we need to talk to resources.
>> What would this routing system look like?  Ignore how Struts is
>> designed today - how would you want such a system to work?  How would
>> you configure it?
>> Don
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail:
>> For additional commands, e-mail:

View this message in context:
Sent from the Struts - Dev mailing list archive at

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message