Edited to address question updates, previous answer removed
Looking over your changes to your question I think I understand the problem you are facing a bit more. As there is no field that is an identifier on your resources (just a link) you have no way to refer to that specific resource within your GUI (i.e. a link to a page describing a specific pet).
The first thing to determine is if a pet ever makes sense without an owner. If we can have a pet without any owner then I would say we need some sort of unique property on the pet that we can use to refer to it. I do not believe this would violate not exposing the ID directly as the actual resource ID would still be tucked away in a link that the REST client wouldn't parse. With that in mind our pet resource may look like:
<Entity type="Pet">
<Link rel="self" href="http://example.com/pets/1" />
<Link rel="owner" href="http://example.com/people/1" />
<UniqueName>Spot</UniqueName>
</Entity>
We can now update the name of that pet from Spot to Fido without having to mess with any actually resource IDs throughout the application. Likewise we can refer to that pet in our GUI with something like:
http://example.com/GUI/pets/Spot
If the pet does not make any sense without an owner (or pets are not allowed in the system without an owner) then we can use the owner as part of the "identity" of the pet in the system:
http://example.com/GUI/owners/John/pets/1 (first pet in the list for John)
One small note, if both Pets and People can exist separate of each-other I would not make the entry point for the API the "People" resource. Instead I would create a more generic resource that would contain a link to People and Pets. It could return a resource that looks like:
<Entity type="ResourceList">
<Link rel="people" href="http://example.com/api/people" />
<Link rel="pets" href="http://example.com/api/pets" />
</Entity>
So by only knowing the first entry point into the API and not processing any of the URLs to figure out system identifiers we can do something like this:
User logs into the application. The REST client accesses the entire list of people resources available which may look like:
<Entity type="Person">
<Link rel="self" href="http://example.com/api/people/1" />
<Pets>
<Link rel="pet" href="http://example.com/api/pets/1" />
<Link rel="pet" href="http://example.com/api/pets/2" />
</Pets>
<UniqueName>John</UniqueName>
</Entity>
<Entity type="Person">
<Link rel="self" href="http://example.com/api/people/2" />
<Pets>
<Link rel="pet" href="http://example.com/api/pets/3" />
</Pets>
<UniqueName>Jane</UniqueName>
</Entity>
The GUI would loop through each resource and print out a list item for each person using the UniqueName as the "id":
<a href="http://example.com/gui/people/1">John</a>
<a href="http://example.com/gui/people/2">Jane</a>
While doing this it could also process each link that it finds with a rel of "pet" and get the pet resource such as:
<Entity type="Pet">
<Link rel="self" href="http://example.com/api/pets/1" />
<Link rel="owner" href="http://example.com/api/people/1" />
<UniqueName>Spot</UniqueName>
</Entity>
Using this it can print a link such as:
<!-- Assumes that a pet can exist without an owner -->
<a href="http://example.com/gui/pets/Spot">Spot</a>
or
<!-- Assumes that a pet MUST have an owner -->
<a href="http://example.com/gui/people/John/pets/Spot">Spot</a>
If we go with the first link and assume that our entry resource has a link with a relation of "pets" the control flow would go something like this in the GUI:
- Page is opened and the pet Spot is requested.
- Load the list of resources from the API entry point.
- Load the resource that is related with the term "pets".
- Look through each resource from the "pets" response and find one that matches Spot.
- Display the information for spot.
Using the second link would be a similar chain of events with the exception being that People is the entry point to the API and we would first get a list of all people in the system, find the one that matches, then find all pets that belong to that person (using the rel tag again) and find the one that is named Spot so we can display the specific information related to it.
Is it appropriate to mix some sort of action call with a resource URI (e.g. /collection/123?action=resendEmail
)? Would it be better to specify the action and pass the resource id to it (e.g. /collection/resendEmail?id=123
)? Is this the wrong way to be going about it? Traditionally (at least with HTTP) the action being performed is the request method (GET, POST, PUT, DELETE), but those don't really allow for custom actions with a resource.
I'd rather model that in a different way, with a collection of resources representing the emails that are to be sent; the sending will be processed by the internals of the service in due course, at which point the corresponding resource will be removed. (Or the user could DELETE the resource early, causing a canceling of the request to do the send.)
Whatever you do, don't put verbs in the resource name! That's the noun (and the query part is the set of adjectives). Nouning verbs weirds REST!
I use the querystring portion of the URL to filter the set of resources returned when querying a collection (e.g. /collection?someField=someval
). Within my API controller I then determine what kind of comparison it is going to do with that field and value. I've found this really doesn't work. I need a way to allow the API user to specify the type of comparison they want to perform.
The best idea I've come up with so far is to allow the API user to specify it as an appendage to the field name (e.g. /collection?someField:gte=someval
- to indicate that it should return resources where someField is greater than or equal to (>=
) whatever someval
is. Is this a good idea? A bad idea? If so, why? Is there a better way to allow the user to specify the type of comparison to perform with the given field and value?
I'd rather specify a general filter clause and have that as an optional query parameter on any request to fetch the contents of the collection. The client can then specify exactly how to restrict the set returned, in whatever way you desire. I'd also worry a bit about the discoverability of the filter/query language; the richer you make it, the harder it is for arbitrary clients to discover. An alternative approach which, at least theoretically, deals with that discoverability issue is to allow making restriction sub-resources of the collection, which clients obtain by POSTing a document describing the restriction to the collection resource. It's still a slight abuse, but at least it's one you can clearly make discoverable!
This sort of discoverability is one of the things that I find least strong with REST.
I often see URI's that look something like /person/123/dogs
to get the persons dogs. I generally have avoided something like that because in the end I figure that by creating a URI like that you are actually just accessing a dogs collection filtered by a specific person ID. It would be equivalent to /dogs?person=123
. Is there ever really a good reason for a REST URI to be more than two levels deep (/collection/resource_id
)?
When the nested collection is truly a sub-feature of the outer collection's member entities, it is reasonable to structure them as a sub-resource. By “sub-feature” I mean something like UML composition relation, where destroying the outer resource naturally means destroying the inner collection.
Other types of collection can be modeled as an HTTP redirect; thus /person/123/dogs
can indeed be responded to by doing a 307 that redirects to /dogs?person=123
. In this case, the collection isn't actually UML composition, but rather UML aggregation. The difference matters; it is significant!
Best Answer
I've used
/profiles/me
before, it doesn't strike me as not representational. Some popular REST APIs have it as well. See this answer on SO.If you're worried about ambiguity, you can always have a fully defined URI alongside the short one pointing to the same resource, and give that one to clients in sensitive contexts.