views:

476

answers:

3

Hi Guys,

I am new to the REST architecural design, however I think I have the basics of it covered.

I have a problem with returning objects from a RESTful call. If I make a request such as http://localhost/{type A}/{id} I will return an instance of A from the database with the specified id.

My question is what happens when A contains a collection of B objects? At the moment the XML I generate returns A with a collection of B objects inside of it. As you can imagine if the B type has a collection of C objects then the XML returned will end up being a quite complicated object graph.

I can't be 100% sure but this feels to be against the RESTful principles, the XML for A should return the fields etc. for A as well as a collection of URI's to the collection of B's that it owns.

Sorry if this is a bit confusing, I can try to elaborate more. This seems like a relatively basic question, however I can't decide which approach is "more" RESTful.

Cheers,

Aidos

+1  A: 

There's nothing saying your REST interface can't be relational.

  1. /bookstore/{bookstoreID}
  2. /bookstore/{bookstoreID}/books
  3. /book/{bookID}

Basically, you have a 1:1 correspondence with your DB schema.

Except for Many-to-Many relations forming child lists. For example, /bookstore/657/books should return a list of book IDs or URLs. Then if you want a specific book's data you can invoke the 3rd URL.

This is just off the top of my head, please debate the merits.

Frank Krueger
+3  A: 

One essential RESTful principle is that everything has a URI.

You have URI's like this.

  • /A/ and /A/id/ to get a list of A's and a specific A. The A response includes the ID's of B's.
  • /B/ and /B/id/ to get a list of B's and a specific B. The B response includes the ID's of C's.
  • /C/ and /C/id/ to get a list of C's and a specific C.

You can, through a series of queries, rebuild the A-B-C structure. You get the A, then get the relevant B's. When getting a B, you get the various C's that are referenced.


Edit

Nothing prevents you from returning more.

For example, you might have the following kinds of URI's.

  • /flat/A/id/, /flat/B/id/ and /flat/C/id/ to return "flat" (i.e., no depth) structures.

  • /deep/A/id/, /deep/B/id/ and /deep/C/id/ to return structures with complete depth.

The /deep/A/id/ would be the entire structure, in a big, nested XML document. Fine for clients that can handle it. /flat/A/id/ would be just the top level in a flat document. Best for clients that can't handle depth.

S.Lott
This is exactly what I was thinking.This of course makes life a little more difficult as I can no longer return objects directly from my DB4O database, I will have to add some conversion code to change the XML output to return URI's instead of the XML representation of the objects.
Aidos
You're not prevented from returning more.
S.Lott
A: 

Make a flat Universe that you expose to the world.

Even when I use SOAP, which can easily handle hierarchical object graphs up to whatever depth, I flatten the graph and link everything with simple IDs (you could even use your database IDs, although the idea is that you want you don't want to expose your PKs to the world).

Your object universe inside your app is not necessarily the same one you expose to the world. Let A have children and let B have children, but there's no need to reflect that in the REST request URLs.

Why flatten? Because then you can do things like fetch the objects later by ID, or send them in bursts (both the same case, more or less)... And better than all that, the request URIs don't change when the object hierarchy changes (object 37252 is always the same, even when it's been reclassed).

Edit: Well, you asked for it... Here's the architecture I ended up using: package: server - contains the superclasses that are shared between the front-end server and the back-end server

package: frontEndServer - contains a Server interface which the front-end server must adhere to. The interface is nice because if you decide to change from SOAP to a straight Web client (that uses JSON or whatever, as well), you've got the interface all laid out. It also contains all the implementations for the frontEnd classes that will be tossed to the client, and all the logic for the interaction between classes except how to talk to the client.

package: backEndServer - contains a Server interface which the back-end server will adhere to. An example of a Server implementation would be one that talks to a MySql DB or one that talks to an XML DB, but the Server interface is neutral. This package also contains all the classes that the implementations of the Server interface use to get work done, and all the logic for the backend except for persistence.

then you have implementation packages for each of these... which include stuff like how to persist for the backend and how to talk to the client for the front end. The front-end implementation package might know, for instance, that a user has logged in, whereas the frontEndServer just knows that it has to implement methods for creating users and logging in.

After beginning to write this up I realize that it would take a while more to describe everything, but here you have the gist of it.

Yar
Thankyou for your opinion on this. Your approach is the same as the one that I was thinking of.As an aside, how would you layer such an application? Have some DO's that are stored in the database (representing the usual structure) and some DTO's that are returned to the client via the REST API?
Aidos
Hey Aidos. Ideally, you don't have to replicate your class structure, but I think it's worth it. The flat classes additionally know how to serialize and deseralize from the real classes, and use only primitives. Is this clear?
Yar
The "flat classes" for you are Data Transfer Objects, of course. Though they should get real names like PCustomerRecord which would be portable customer record.
Yar
I'll answer this within the next 24 hours. I have such an app, so I can describe it to you. I tried to do everything with interfaces to make all parts replaceable... I'll detail that in my answer here.
Yar
Daniel, thanks - that is something that I would be definately interested in seeing!
Aidos
Sure. How could I possibly get best answer without ever getting voted up by anybody? Just curious...
Yar
Love the downvotes from people... why?
Yar