I worked out 3 alternatives that may solve this issue, which is a very important one IMHO.
---- 1st alternative ----
If your Trip's Id is calculated from another attribute, there is a way. Instead of getting the Trip
by its id
get it from that other calculated property. Let's imagine your Trip's id is calculated by some canonical name (A URN you infer from its full title), e.g. if the Trip's full name is
Voyage to the Everest
your canonical name may be voyage-to-the-everest
and this is the String you use as name for the Key. So instead of getting the element using datastore.get
use:
@Override
public Optional<Trip> findById(String tripCanonicalName) {
StructuredQuery.PropertyFilter eqTripCanonicalName = StructuredQuery.PropertyFilter
.eq("canonicalName", tripCanonicalName);
EntityQuery query = Query.newEntityQueryBuilder().setKind("Trip")
.setFilter(eqTripCanonicalName).setLimit(1).build();
QueryResults<Entity> results = getDatastoreService().run(query);
if (results.hasNext()) {
return Optional.of(fromEntity(results.next()));
}
return Optional.empty();
}
this will get the entity (Trip
) no matter whose parent (User
) be.
---- 2nd alternative ----
Before accessing an element probably you first have to list them and then select one and go to an access link. As we know using the id of the task wont be enough because it will be unique only for its parent (User
), but instead of showing that id
you may use the url safe id:
entity.getKey().toUrlSafe()
so in the conversion from entity to object assign the Task
element this id encoded in a base-64 encode. To get the key back from the url safe use
Key.fromUrlSafe
It will guarantee you will always gonna use a global unique id.
---- 3rd alternative ----
Using HATEOAS you can specify the link for accesing the Task
, so if the task has some id such as parentId
or userId
which is basically getting his parent node's id, it could be very easy for you to stablish a link pointing to a url like this
http://base-url.com/users/{userId}/tasks/{taskId}
So in a HATEOAS request this could be indicated in the links, that indicates the allowed actions for the element, so for viewing the element use self
, e.g
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"userId": "my-traveler-user-id",
"_links":{
"self":{
"href":"http://localhost:8080/users/my-traveler-user-id/tasks/voyage-to-the-everest
}
}
}
If instead of a userId
you use a parentId
you may work it out with an interface where all the nodes specify if they have a parent or not. Even it could be more flexible with a parent
property where you define the whole parent hierarchy:
public interface DatastoreNode{
String getParentId();
String getParentKind();
String getParentUrlTag();
DatastoreNode getParent();
}
Although HATEOAS is strongly recommended you can infer the same url having a json structure such as
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}