tags:

views:

112

answers:

3

I am working on a REST based API, and having some trouble figuring out what the canonical way is to represent parent / child relationships. (I am writing beans in CXF and using JAX-RS and JAXB. I started from the basic example provided by CXF)

My problem is let's say you have a Foo and a Bar. There is a 1-N relationship with Foo and Bar, that is 1 Foo has many Bars. My question is, what's the canonical way to find out what Bars a Foo has? And what's the canonical way to access Bar resources owned by the Foo?

I have figured out that for example I might list Foos at:

GET http://xxx/fooservice/foos

And operate on a single foo at:

PUT/UPDATE/DELETE http://xxx/fooservice/foo/{fooid}

But how do I list Bars that Foo 121 has? And how do I access them? I've noticed that it seems the default JAXB marshaller doesn't output Collections just attributes for a bean, so if a Foo is:

Foo
  - String id
  - String name
  - Collection bars

JAXB outputs something like:

<foo><id>123>/id><name>foo name</name></foo> <-- note the absence of the bars attribute

Which is problematic, as there is no way for the client to reasonably be expected to know that Foo has Bars, unless it "just knows" (which seems bad to me). So while I can imagine to get a list of bars using:

GET http://xxx/fooservice/foo/121/bars

How does a client know that Foo has Bars if the output of the entity doesn't say anything about it? Now presuming the client does get the list, then it seems entity operations would be something like:

GET/DELETE/UPDATE http://xxx/fooservice/foo/121/bar/435

which would access Bar 435 owned by Foo 121.

A: 

What you want to do is certainly possible. One way of designing the resources is:

/foos
          # A list of all the Foo resource names (not representations).

/foo/{fooid}
          # A detailed representation of a particular Foo, including 
          #   a list of all that Foo's Bar resource names (not representations).

/foo/{fooid}/bar/{barid}
          # A detailed representation of a particular Bar.

You may have a situation where the Bars have no real existence outside of a particular Foo (as in a purchase order's master and the detail rows it contains). If this is the case, and each Foo hasn't got all that much Bar data to go with it, you could return the full Bar details right in the Foo representation:

/foos
          # A list of all the Foo resource names (not representations).

/foo/{fooid}
          # A detailed representation of a particular Foo, including 
          #   full details on each of its Bars.

You generally want coarser granularity with REST resources. Note that if you choose this, then to modify a Foo's Bars, you'd GET the Foo, modify the Bar's in the Foo representation, and then PUT the Foo.

Not sure what's happening with your serialized XML representations, you should create a second question with the relevant code.

Jim Ferrans
A: 

Thanks for the detailed post - what you describe is basically already what I am doing without the detailed representation of Bars inside each Foo as you suggest so it seems I had it mostly right.

I will find out why the Collection of Bars inside a Foo is not getting unmarshalled as XML in JAXB in a separate Q as you suggest.

Taylor Gautier
A: 

Taylor, Jersey's implementation of JAX-RS certainly does emit the List properties of objects that it converts into XML or JSON. So in an app I just finished, the UserStore object has a property, users, that's a List:

List<User> users = new ArrayList<User>();

When I use Jersey to emit the XML or JSON version of the UserStore, I get an array of users for that property:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<users>
    <user>
     <firstName>John</firstName>
     <id>a29a377f-4329-4ec8-9459-b5b1c2efc38a</id>
     <lastName>Doe</lastName>
    </user>
    <user>
     <firstName>Jane</firstName>
     <id>bb4dad28-1263-440a-afc5-062a8566ef90</id>
     <lastName>Roe</lastName>
    </user>
</users>

and

{
    "user": [{
        "firstName": "John",
        "id": "a29a377f-4329-4ec8-9459-b5b1c2efc38a",
        "lastName": "Doe",
    },
    {
        "firstName": "Jane",
        "id": "bb4dad28-1263-440a-afc5-062a8566ef90",
        "lastName": "Roe",
    }]
}

Perhaps the issue you're running into is merely related to your property being a Collection rather than a List...

delfuego