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.
The general underlying answer here is that your ideas may work on a technical level, but that doesn't mean they conform to the standardized conventions of REST.
- PUT/PATCH - What is the point of passing in the entire resource for modification? I only use PUTs to modify resources, and I only pass in the fields I want to be updated. As a result, I have no need to use PATCH
Your idea works on a technical level, but it's simply not how REST has been described. Keep in mind that any discussion about working code (i.e. no compile or runtime errors) is always going to be a matter of convention, not necessarily of clear technical superiority.
- Resource Paths - I use GUIDs in my application. As a result, they will be globally unique. Why do I need the full resource path, including the parent resources, if I can just uniquely refer to a subresource by itself?
There are many nuances to how we define "child/parent" entities. Most commonly, it refers for a one-to-many (parent-to-children) relationship.
However I suspect that for REST, part of what makes a child a child is that there is an expectation of only being able access them through the parent, that they don't carry their own globally unique (and externally known) identifier.
I suspect this is following the same philosophy (but not necessarily for the same reason) as that of aggregates (and their roots) in Domain Driven Development.
A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An aggregate will have one of its component objects be the aggregate root. Any references from outside the aggregate should only go to the aggregate root.
In your case, what you call the "parent" functions as the aggregate root. The single point of contact (if you will) for outside callers.
You might want to conclude from this that your child is actually a different aggregate. That may be the case, but I do want to issue a warning with that decision. You shouldn't base your architecture on the particular type of a field. You have no way of knowing if you will always keep using globally unique IDs for all your entities. If that ever changes, for whatever reason, you're going to compromise the viability of your REST architecture; as you may end up in a situation where the child is no longer uniquely identifiable and thus needs to be referenced through its parent.
- If I POST to create a new resource, PUT to update, or DELETE to remove, I want to see the deltas in the tree, rather than just seeing the resource that I created/updated/deleted.
You're violating the order of operations of the design. A REST API is specifically intended to be consumer agnostic. The API should not be built according to the specifications of one of its consumers.
When you say "I want to see the deltas in the tree", what you're really saying is "the consuming application only has a need to see the deltas in the tree". But that doesn't quite matter to the REST api. It merely provides a standardized approach.
It is the nature of standardized approaches to often lack highly customizable tools, and instead favor the most commonly used tools.
Can you deviate from the path? Well, it will work on a technical level. But it won't be pure REST anymore. This is something that is highly contextual and you need to weigh the options.
- If you're creating an API that is expected to cater to many varied consumers, then I suggest sticking to REST as best as you can.
- If you're building an API that will only have one consumer which is also developed by you; then there's no real need to stick to pure REST.
- Straying from the path means you're going to have to document how you've strayed so other developers can still make sense of it. If you stick to pure REST, you don't have to write the documentation and the other developers don't have to spend time and effort figuring out your customized approach.
Best Answer
Using random routes...bad design.
In regards to nesting, lets take a use case where you have a set of users and a set of books, and a certain user can have multiple books associated
It would then make sense to have:
/users
- get users, you can use query params for pagination, sorting and filtering/books
- get books/users/{user_id}/books
- get the books associated to a certain user, thus having a natural nesting, reflected by your data model as wellThis was just a simple example, hoped in helped, for a better understanding I would suggest googleing for something like rest api desing best practices, go over multiple sources and try to adapt something that feels ok to you and also makes sense from the app requirements point of view