[uf-rest] RESTifying RAILs

Dan Kubb dan.kubb at autopilotmarketing.com
Thu Nov 10 10:50:25 PST 2005


Hi David,

> But more importantly, I reckon that lots of pages won't rely simply  
> on a single resource to compute whether they're stale or not. At  
> least that's not the use model I've been finding to be true.

You're right about that, multiple models are involved in the creation
of most pages.

We'd need to look at all the models and use the latest updated_at
value for Last-Modified and some sort of combination of all the model's
lock_version values for ETag.

> class WeblogController < RestController
>   verbs_for :index do
>     def get
>       @person = Person.new(params[:id])
>       render :modified_at => @person.updated_at
>     end
>   end
> end
>
> This would by default just produce a :etag based on the :modified_at,

There's no real need to send an ETag that is just a copy of the
Last-Modified value.  Compliant clients submitting conditional requests
will use Last-Modified on its own as If-Modified-Since and If- 
Unmodified-Since
headers.  Good conditional handling code will use as many headers
as are available.

> but you would also be allowed to set that explicitly ala:
>
>   render :modified_at => @person.updated_at, :etag =>  
> @person.lock_version

I do think it should be possible to pass in the modified_at and
etag into render, but there should be a way to easily set the Last- 
Modified
and ETag headers earlier on in the request *before* render.

Consider handling conditional PUT:

class WeblogController < RestController
   verbs_for :index do
     def get
       @person = Person.new(params[:id])
       modified_at << @person.updated_at
       etag        << @person.lock_version
     end

     def put
       get
       @person.save if meets_condition?
     end
   end
end

In the above example if the client sends the If-Match and/or
If-Unmodified-Since headers and they match up with the response
ETag and/or Last-Modified headers then (and only then) the
person will be saved.

A good meets_condition? method will also handle cases where no
If-* header is sent by the client, and return true, so that the
save will be processed.  This is useful when dealing with clients
that don't support any conditionals, such as older browsers,
everything will just work for them as before.

This all would work fine as a lower level way of setting the ETag
and the Last-Modified headers (although not quite as low as the
headers method) but I wonder if there should be a higher level of
abstraction that allows people to do the right thing without needing
to know as much about HTTP:

class WeblogController < RestController
   verbs_for :index do
     def get
       resources << @person = Person.new(params[:id])
     end

     def put
       get
       @person.save if modify_resource?
     end
   end
end

I'm fairly new to ruby, but the append (<<) operator seemed
to be the most natural to say "add this object to the collection
that may be used in the response".

I think the key to getting something like this used is to
hide some of the details of HTTP.

> Because then we could use better composite models ala:
>
> class WeblogController < RestController
>   verbs_for :index do
>     def get
>       @posts    = Post.find(:all, :order => "updated_at")
>       @comments = Comments.find(:all, :order => "updated_at")
>       render :modified_at =>
>         @posts.first.updated_at > @comments.first.updated_at ?
>            @posts.first.updated_at : @comments.first.updated_at
>     end
>   end
> end
>
> Or something less contrived, but you get the drift. Lots of pages  
> are not bound to merely 1 model. Being a little more explicit opens  
> it up to wider usage, me thinks.

The above case could be handled with the simpler API I outlined
earlier:

class WeblogController < RestController
   verbs_for :index do
     def get
       @posts    = Post.find(:all, :order => "updated_at")
       @comments = Comments.find(:all, :order => "updated_at")
       resources << @posts.first
       resources << @comments.first
     end
   end
end

Or is that coupling things too tightly?

--

Thanks,

Dan
__________________________________________________________________

Dan Kubb                  Email: dan.kubb at autopilotmarketing.com
Autopilot Marketing Inc.  Phone: 1 (604) 820-0212
                             Web: http://www.autopilotmarketing.com
__________________________________________________________________





More information about the microformats-rest mailing list