Ahh!  I see your question now.  I'm sorry I derailed us.

You're asking what's the best practice to use when coding your Resource.

Of course, this is only my advice, as I'm sure other people do it other ways. I don't even know if there is a "best practice," since obviously each situation is different...

I usually follow approach #4. That is, I add in some simple Variants during init(), and then use the allowGet()/getRepresentation() or allowDelete()/delete() methods to do any connecting to the database. I don't think this is working cross purpose to the API. In fact, not that I can speak for the API designers, I believe #4 is the approach they had envisioned.

My Variant is created during construction time. Ie. getVariants().add(new Variant(MediaType.XYZ));

This approach allows the library to do the automatic content negotiation and call getRepresentation(Variant v) with the appropriate Variant. If you short circuit this and add in your Representation during construction, basically you miss out on the ability to "switch" on the Variant coming into the getRepresentation method. Obviously you can do this content type negotiation yourself in the constructor, but why... It's already being done for you.

Therefore, I do not try and do any testing of the request coming in during the constructor or in the init() method. I believe these methods should basically return pretty quickly after setting up the Variant (as above).

You're right in that there is no representation of the resource when doing a delete. Therefore, it's a little bit silly to setup a Resource class (along with the Variant) just to delete a resource. Like I said though, I don't actually create the Representation during construction and instead rely on the delete() method to be called.

Doing it this way, like you say, is less work and only requires at most one database request to the backend. I would definitely recommend avoiding the double trip to the database as in your first couple of examples.

Finally, WRT efficiency... If you are running into bottlenecks or slowdowns in creating the Resource classes (since they are created for each request), perhaps you could do a couple of things: a) create a Resource pool; b) use a Filter (or other Restlet type) to intercept DELETE requests and not allow the request to create a Resource. Simply intercept the delete request, perform the deletion, and block the call back through to the Resource creator (ie. the default Finder class).

Anyway, I would opt for #4 first. If you suffer performance penalties (I don't know if you would), then you could optimize at that point.

Now, did that answer your question??  I hope so...  :)

Adam


Geoffrey Wiseman wrote:
Adam Taft <adam <at> adamtaft.com> writes:
a) GET should NEVER! change the state of an object. I'm confused as to how/why you are mixing a DELETE operation and a GET operation together. I'm probably mis-reading.

Yes, I must not have been clear.  My GETs aren't changing the state of an
object, nor are the GET and DELETE mixed together.  I was just using an example
of a situation where I have a resource that supports both GET and DELETE.

So in that situation, I can:

1 - Create a representation in the Constructor
When the resource is constructed, I can retrieve the resource from the
datastore, and if it exists, create a representation and drop it in the variants.

If it's a DELETE, I ignore the representation and delete in the datastore.  The
representation, and the time to create it, are wasted.  Two round-trips to the
database here where only one was necessary.

If it's a GET, I do nothing; the representation is already there or it isn't,
and RESTlet can decide to 404 or 200-with-representation, I don't have to do any
work.

2 - Check for Existence in Constructor
When the resource object is constructed, I can check to see if the resource
exists in the datastore.  If it does, I can drop a variant in the variants,
otherwise I do nothing.
If it's a DELETE, I can use the information I gathered in the constructor to
delete the representation.  Once again, this is two round-trips to the database
where only one was necessary (if the resource exists).

If it's a GET, I can use the information I gathered to create a representation.
 This might be another database call, so this could again be wasteful.

3 - Check Method in Constructor
If it's a DELETE, there's no real reason to look in the database in the
constructor; I'd prefer the DELETE to be idempotent, so I don't want to 404
anyway.  So, I could decide to only check for a representation and populate the
variants if the method is GET.
This is functional, and not very wasteful, but feels like I'm working at
cross-purposes with the API.  It's already got branching on methods, but I'm
going to put a method-conditional in the constructor?

4 - Do The Work Later
Do very little in the constructor; toss in a variant in the hopes the resource
exists.

If it's a GET, I work in getRepresentation(Variant) to check if the resource
exists.  If it does, I return a null variant and set the status code.

If it's a DELETE, I issue a SQL delete that may or may not remove a record and
do nothing else.

This approach does the least work, so is probably the best from a performance
perspective, but it again feels like I'm working a little cross-purposes in the API by bypassing all that "If there's no variant, then 404" code in Resource.

Actually, I'd be happy with this if Resource.handleGet() treated a null from
getRepresentation as a 404, but that might not work for all cases?

--

So is that more clear?

GET should only retrieve a representation. Usually, most GET requests have some sort of candidate-key associated to them (in the URL string) that can uniquely identify the resource. All you should have to do is start querying your database. If at the point in time you perform the query, the record is not in the database, the query result will tell you this (the size of the result set, or other means).

So, just simply retrieve the object. If it's in the database, great. Return 200. If not, return 404:

Sure -- you're proposing to do this all in getRepresentation(), as in my #4 above?

b) DELETE should NEVER! return a 404. Your server should be happy to accept DELETE requests to any (logical) resource, whether or not that resource actually exists or not.

Sorry, I didn't mean to imply that I wanted to 404 the DELETE.

This comes back to the basic definition of REST: Representational State Transfer. When you delete a resource, you're really asking that the state of the resource be moved into the 'deleted' state. If a resource is already in the deleted state, that doesn't matter.

Well, a resource that never existed isn't in the "deleted" state per se, but I know what you mean, and agree.

Just let your transactions come in which ever order they come in. If a GET comes before a DELETE, or vice versa, that's ok. I think you're trying to tie the two together or something?

Nope; hopefully the above clarifies my intent somewhat.

 - Geoffrey

Reply via email to