12

How to I represent a complex resource for a REST post?

Hello, Currently I have an application which when the user hits "save" it iterates over all of the form elements and creates one mass object which manages a:

  var = params = [{ 
   attributes1: form1.getValues(),
   attributes2: form2.getValues(),  
.. ..
}];

I then send this mass object via a RPC POST to my "Entity" model service. This entity which I wish to persist data for is quite complex. All in all, the data is spread accross about 30 tables. To help explain my actual question, the "entity" is a building (as in a physical property/house/apartment).

What I would like, is to be able to turn my mess into a RESTful API for saving properties. The problem I have is that, saving details for a single model that spans a single table is fine. How do I structure my data object for transport when the model has

  • many to many relationships
  • one to many relationships
  • one to one relationships

For example:

Here is a WATERED down version of what I might have on a property and the sample data

propertyId: 1,
locationId: 231234,
propertyName: "Brentwood",
kitchenFeatures: [
             { featureId: 1, details: "Induction hob"},
             { featureId:23, details: "900W microwave"}
],
propertyThemes: [ 12,32,54,65 ]

This actually goes on a lot more.. but you can get the general gist. kitchenFeatures would be an example of a many-to-many, where I have a featuresTable which has all of the features like so:

`featureId`, `feature`
1             "Oven Hob"  
23            "Microwave"

and propertyThemes would be an example of another many-to-many.

How am I expected to form my "object" to my RESTful service? Is this even possible?

ie. If I want to save this property I would send it to:

http://example.com/api/property/1

Layke
  • 51,422
  • 11
  • 85
  • 111

3 Answers3

10

The approach I would use here is hypermedia and links:

/property
/property/{id}
/property/{id}/features/{id}

Depending on your domain you might even get away with:

/property/{id}/features/{name}

or

/property/{id}/features/byname/{name}

Thus you can do REST operations and serve JSON or XHTML hypermedia.

Property details:

Request: GET /property/1
Response:
{
  ..
  "name": "Brentwood",
  "features": "/property/1/features"
  ..
}

Brentwood's features:

GET /property/1/features
{
  ..
  "Kitchen": "/property/1/features/1",
  "Dog Room": "/property/1/features/dog%20room",
  ..
}

GET /property/1/features/1
{
  ..
  "Induction hob": "/property/1/features/1/1",
  "900W microwave": "/property/1/features/1/23",
  "nav-next" : "/property/1/features/dog%20room",
  ..
}

To add a relation you can do something like this:

POST /property/1/features
{
  ..
  "Name": "Oven Hob"
  ..
}

If you know what the relation will be you use a PUT:

PUT /property/1/features/23
{
  ..
  "Name": "Oven Hob"
  ..
}

You can serve multiple media types:

GET http://host/property/1/features/dog%20room.json

GET http://host/property/1/features/dog%20room.xhtml

For the response in xhtml the response can use named links like this:

..
 <a href="http://host/property/1/features/1" rel="prev">Kitchen</a>
..

There are other aspects of REST that you can use such as response code which I did not include above.

Thus, to model relations you make use of links which can be in itself a resource that can be operated on with GET, PUT, POST and DELETE or even custom verbs such as ASSOCIATE or LINK. But the first four are the ones that people are used to. Remember PUT is idempotent but not POST. See PUT vs POST in REST

Edit: You can group your links into JSON arrays to give structure to your hypermedia.

Community
  • 1
  • 1
Derick Schoonbee
  • 2,971
  • 1
  • 23
  • 39
4

I think you're really asking, "How do I represent complex data in a form suitable for transmission within a POST?", right? It's less to do with REST and more to do with your choice of media type. I would suggest starting with a pure JSON representation, using arrays and cross-referenced ID fields to map the relationships. You could also do this with XML, of course.

The examples you gave look right on the money. You just need to ensure that both parties (browser and server) agree on the structure and interpretation of the media type you use.

Brian Kelly
  • 19,067
  • 4
  • 53
  • 55
  • Brian, yes, you are correct. My question really boils down to: "how do I represent a complex resource which features dozens of relationships". I can't actually find many articles/resources on this topic. If I just reference the IDs, that isn't restful is it? – Layke Mar 25 '11 at 08:57
  • Absolutely, yes. The only thing I would ensure is that you are transmitting the entire representation of the object graph around and not just a partial amount. Of course, you could go "super-pure" with your approach and degrade your single POST call into lots of POST calls (one for each object that you need to create) but I would think that would be an arbitrary decision that would only force you to make dozens -- if not hundreds -- of remote calls. It really depends on what your application requires. – Brian Kelly Mar 25 '11 at 14:24
2

I'm dealing with the exact same thing. I opted to not use id's anywhere, but use urls everywhere an id would normally be expected.

So in your case, the kitchenfeatures could simply be an array with urls to:

/feature/1
/feature/23

And the themes to

/propertyTheme/12
/propertyTheme/32
etc..

In the case of many-to-many relationships, we update all the relations as a whole. Usually we simply dump the existing data, and insert the new relationships.

For one to many relationships we sometimes extend the urls a bit where this makes sense. If you were to have comments functionality on a 'property', this could look like

/property/1/comment/5

But this really depends on the situation for us, for other cases we put it in the top-level namespace.

Is this helpful to you?

Evert
  • 93,428
  • 18
  • 118
  • 189
  • Doesn't that mean that your client dictates to the server what URI it must use for each newly-created object, though? That's something I would try to avoid, given that it should be the server's decision what URIs look like. Or does your client already have those URIs available to it from previous POSTs? – Brian Kelly Mar 30 '11 at 14:16
  • Since you're talking about many-to-many, I asummed what you're relating to (features) already exists. So the client would have those uri's available. Is this assumption wrong? – Evert Mar 30 '11 at 14:42
  • I think we'll need the OP to answer that. I had assumed the opposite, that the client was basically creating an entire graph in one fell swoop. – Brian Kelly Mar 30 '11 at 15:28