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.
What you want to do is certainly possible. One way of designing the resources is:
/foo
# 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:
/foo
# 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 Bars 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.
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, 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...
for me this question answer is going to be driven by data modeling, and for data modeling the question is "using composite key for child model or not" if he is using composite key so you have to put the parent id in URI if not and child have its own id which is not composite so you can just use URL with child id only.
so this is data modeling question!!!