-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi Charlie,
==== Syntax ==========
The currently proposed syntax is:
resource :collection do |r|
r.post do
end
end
Where 'r' is an instance of a Resource class. At first I preferred
a simpler syntax, like this:
resource :collection do
method.post do
end
end
Where method represents the HTTP verb (GET, POST, PUT)? Or maybe
even:
resource :collection do
request.post? do
end
end
However, do you have to have an instance of the resource class to
achieve the 4 points you brought up (more details in original email):
1. Handling OPTIONS requests.
2. Returning 405 when appropriate
3. Return 501 when appropriate
4. Checking If-* request
These all would be good features to have. If they require having a
resource class passed as "r" then I can agree to this approach.
To do the first three of the above you need to keep track of which
HTTP methods have handlers defined for them. I thought the most
obvious place would be in a "resource" object, since in REST terms
you call methods on a resource.
To do the fourth option you need to check the If-* headers AFTER
you've instantiated all the models that could affect the output of
the representation (view) or the logic in the per-method handler,
but BEFORE you actually run the per-method specific code.
So the pattern is:
resource :collection do |r|
# instantiate models
# register models as conditions affecting the display of
# the representation or affecting the logic in the per-method
handler
# check the If-* headers against the server state before executing
# the per-method handler
# execute per method handler
end
I still think I prefer the top-most syntax. In fact, I think the third
one could potentially introduce bugs because of the 4 steps that are
performed. I suppose you could get around that by explicitly testing
the conditions, but its not really necessary, most people will forget,
and should ALWAYS be performed before executing the per-method handler.
==== Templates ==========
You mentioned that you'd expect these responses for different methods:
GET - 200 OK - Response Body
POST - 303 See Other - No Response Body, Location header to
newly created resource
PUT - 303 See Other - No Response Body, Location header to
resource
DELETE - 303 See Other - No Response Body, Location header to
collection resource
Using regular HTML forms I'd agree. However, this breaks down when
using XmlHttpRequest.
This response pattern is not what I'd recommend when doing AJAX
stuff. I would only
do this when forced to tunnel PUT/DELETE over top of POST when using
HTML forms,
which is an altogether different scenario than an AJAX client. An
AJAX client doesn't
have to do any tunneling, since it can issue a true PUT or DELETE on
its own.
The response pattern I normally use for web services (including AJAX
clients) is the
following:
GET - 200 OK - Response Body
POST - 201 Created - No Response Body, Location header to
newly created resource
PUT - 204 No Content - No Response Body
DELETE - 204 No Content - No Response Body
I'm very particular about what headers and response body I return for
specific methods. I suppose some people would execute a PUT, and then
return the same response body as you'd get when issuing a GET in order
to cut out a round-trip to the server. To me that smells like a
premature
optimization of sorts. I'd prefer to keep the API simple and
consistent,
and if I need to know the current state of the resource I'll perform a
Conditional GET on the resource, not rely on a "PUTGET" to know the
state.
I'm not saying these two patterns are the best ways to respond to
specific
HTTP methods, I'm just saying that they've worked well in all the cases
I've personally tested.
Thus, I think we must provide a system where you can provide a
response body regardless of the method. One approach is Peter's
proposal of just using a standardized directory structure:
view
my_controller
resource1
get
put
resource2
post
delete
I like this concept. However, maybe it would be confusing since
Rails uses directories for nested classes
(MyNamespace::MySubNamespace::MyController). Thus, we could go use
the name mangling I currently do now, i.e., get_resource1, or
resource1_get (which I like better because it groups the templates
for a resource together a bit more clearly).
Since I follow the response patterns I outlined above, I'd never need
this
sort of directory structure, so to me it adds unnecessary
complexity. I'd
personally hold off on this until a pattern emerges in working code and
ONLY if adopting this convention reduces code consistently across the
code base.
For example, if you had a ton of code that looked like this:
resource :collection do |r|
# ... get the models ...
r.post do
# ... do some work ...
render :template => 'collection_post'
end
r.put do
# ... do some work ...
render :template => 'collection_put'
end
end
Then I'd say go with it. But if you attempt to use the patterns I
outlined
above, I don't think you'll see it too often.
I've mentioned before, but I'm always cautious about breaking
fundamental Rails
conventions for our own purposes, like the naming and location of
templates.
There's so much already out in the wild that relies on those
conventions that
to break one means that you suddenly have to re-implement other
functionality
that rely on those conventions. Maybe in this particular case it
won't be
a big deal (I don't know), but we get alot for free with rails and
I'd like
to keep as much as I can by sticking with conventions by default.
==== Top Level Resources ==========
Here is something Peter and I disagree about. Do you prefer this
style:
def MyController
resource :collection do |r|
...
end
resource :member do |r|
...
end
resource :editor do |r|
...
end
end
Or this:
def MyController
r.get
...
end
r.post
...
end
resource :member do |r|
...
end
resource :editor do |r|
...
end
end
The difference being in the first case you insist every resource
must be defined via "resource" while in the second you say that the
controller is the top level resource. When I first did my
RestController I went with option #1 because it seemed more
elegant. However, I quickly changed my mind when actually writing
code because it turned out to be annoying having to add the extra
syntax. This was particularly true for controllers that are just
single resources. For example, say you have geocoding
functionality so you have a GeocoderController. It does just one
thing, GETs geocoding results so there is no concept of collection/
member. Thus I favor option #2 as a syntax shortcut.
I prefer the first style for a couple of reasons.
The first one is esthetics. I like my APIs to be consistent, whether
in web
services or programming. I don't like the idea of having one way to
define
a "default" resource as opposed to a normal resource. Maybe I'm taking
a page out of DHH's Emo Programmer, but it gives me cold shivers rather
than warm fuzzies ;)
The second one is that its really close to the rails way of doing
things. If
we tell developers "the resource method creates normal rails actions
named
collection, member and editor in this case." Simple. Its so easy to
tell
people who are trying to wrap their heads around it to do a s/
resource/action/
in order form the mental bridge between Rails and REST.
The third one seems to be sort of an optimization again. It cuts out
only
two lines of code and I can't help but feeling it would add a little
bit of
cognitive overhead to others having to maintain it.. I know I had to
do a
double-take when I first saw the syntax on your blog last week.
And fourthly it means you can't gather up all the models before
executing
the per-method HTTP handler. That means you'll either have duplicate
code
in each of the handlers, or you'll be using a before_filter to do the
work.
And if you're not using the same model objects in each of the per-method
handlers then I would argue that you don't have a single resource, but
rather two or more distinct resources that should have their own
per-method handlers.
==== Caching ==========
Sounds like we've agreed that caching is important, but is not part
of the Rest Controller. Thus, you'll split that off the caching
functionality into another plugin that can work with a Rest
Controller.
Yes, I will work on this next week. It should be relatively simple.
I'm
probably going to do it after I update before_filter to add a way to
specify them on a per HTTP method basis.
==== Implementation ==========
I see that your implementation is significantly different than
mine. I map :resource to a Ruby module, which gets included in a
controller. In contrast, you map :resource to a Ruby method.
Within that method you create an instance of a Ruby class called
Resource and then execute the provided block in its context. This
disadvantage of my approach is that there is method renaming that
goes on under the scenes, which you have to know about in order to
get filters to work correctly. The disadvantage I see to your
implementation is that all the methods for a resource get mapped
under a single Ruby method. It seems that would make it hard to
apply filters to specific methods.
I.E., how could I apply a filter to a GET method of the resource
Member but not to the POST? It would be great if we could use the
existing filter syntax without change, but I'm guessing that might
not be reasonable because now we are dealing with Resources and
Methods as opposed to Actions. Anyway, this is something I think
is important to solve.
It should be relatively simple. A filter runs before the action ever
executes, so
it doesn't have to know anything about the way the action is being
handled. It should
simply be a matter of wrapping an old before_filter in a Proc that
checks to see
if @request.method matches a list of allowed methods. Maybe 2 or 3
lines of code.
I was thinking of using Peter's proposed syntax, which adds
the :methods condition:
before_filter :auth, :methods => [ :post, :put, :delete ]
So in this example we'd run the rails auth method whenever the HTTP
request
method is either POST, PUT or DELETE. Of course, you could still
restrict
it further by using the :only condition to specify exactly which
actions/resources to apply the filter to.
I think this would be nice to add to Rails core, but for now I'll add
it to my
Rails Controller. I'd also make sure after and around filters could
use the
same syntax.
Also, how does your Rest controller interact with the base
ActionController? I'm not seeing it being include anywhere...could
you point me to the appropriate code.
Its supposed to be included at the top of the controller (just like
yours)
with "include RestController::Base".
Last, it would be good to have an example controller for people to
play with. Something simple, like a ProductController or mabye
copying one of the examples from the Agile Web Development book.
For the most part the example at
http://microformats.org/discuss/mail/microformats-rest/2006-March/
000158.html
should work.
People can use the original syntax:
def new
resource.post do
end
end
Or the proposed syntax, which I added yesterday so people could try
it out now
while we thresh out the design on this list:
resource :new do |r|
r.post do
end
end
- --
Thanks,
Dan
__________________________________________________________________
Dan Kubb
Autopilot Marketing Inc.
Email: [EMAIL PROTECTED]
Phone: 1 (604) 820-0212
Web: http://autopilotmarketing.com/
vCard: http://autopilotmarketing.com/~dan.kubb/vcard
__________________________________________________________________
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (Darwin)
iD8DBQFELydh4DfZD7OEWk0RApinAKCfLe+LM9oo1XhpQcz58LlE0QjJNQCgp1RP
lEnzmkMObzdguxA1zu1e9aM=
=6tBC
-----END PGP SIGNATURE-----
_______________________________________________
microformats-rest mailing list
[email protected]
http://microformats.org/mailman/listinfo/microformats-rest