authzed-node
authzed-node copied to clipboard
Add examples for reading relationships in the node client
We're diving into SpiceDb and currently focused on syncing relationships from various data sources. Our approach involves an initial "full sync" from relevant databases, creating relationships. Subsequently, we aim to perform continuous updates by handling single new relationships as they occur in our databases. However, we're encountering a challenge during the full sync, where fetching data from an API and creating relationships works fine initially. Still, on subsequent triggers, it fails due to attempting to create an already existing relationship.
One quick, short-term solution to this was to use RelationshipUpdate_Operation.TOUCH
instead of CREATE
, but on the long run, we would like to be able to read existing relationships, so on subsequent triggers, we can control creating new relationships, as well as deleting the ones that are out of sync.
To address this, we've devised a strategy to fetch all existing relationships of a specific type and then appropriately skip existing ones, delete, or create single relationships.
We are currently getting stuck at just reading all the existing relationships of a type…
Here's an overview:
We've defined two entities in our schema - team
and employee
. The team has a member
relation with employee
. Our goal is to read relationships for a specific resource, where the relation is member
, essentially fetching all employees that are members of a particular team.
We've crafted a function utilizing the SpiceDb API to read relationships. The function, responsible for reading existing relationships, follows these steps:
- Defining an
ObjectReference
for the entity using thev1.ObjectReference.create
method. - Creating a
ReadRelationshipsRequest
specifying details about the relationship to be read. It includes theObjectReference
and sets the relation tomember
-
gRPC
: Invokingclient.readRelationships
method with the definedreadRelationshipsRequest
.
Currently, we get the error: "Cannot read properties of undefined (reading 'create')."
Would be useful to have some documentation available on the correct procedure for this, to be able to assess where I might be going wrong.
@MadaPas A good source of reference might be here:
GitPod seems to have a pretty decent Spice client implementation written in TS.
https://github.com/gitpod-io/gitpod/blob/df7929ce8a971da4cfac1e72d3c64473ca65097e/components/server/src/authorization/relationship-updater.ts
Hi! I'm struggling to navigate the TypeScript solution, and it seems a bit complex... Do you have plans to enhance the Node client in the near future, perhaps with additional examples focusing on reading relationships?
Hi @MadaPas! Gitpod has been using SpiceDB for a while now, so their client is definitely more developed and harder to learn from.
Do you have plans to enhance the Node client in the near future, perhaps with additional examples focusing on reading relationships?
The team has discussed improving the documentation for the different clients, especially the TypeScript client since it is one of the most widely used. What kind of examples would be most valuable to you? We could start with just adding usage examples for each method.
Currently, we get the error: "Cannot read properties of undefined (reading 'create')."
For this error specifically, could you include a small code snippet? I suspect this is something very simple.
P.S. The SpiceDB team and community is very active on Discord too and can help walk you though other issues you might be having.
@MadaPas Are you still having trouble with the ReadRelationships API?
Hi @alecmerdler !
So sorry for keeping this issue open without an answer for so long. We changed our goals and have not worked on this recently, but will be picked up very soon (next week).
But to answer your question, no, I don't have issues with ReadRelationships
anymore 🙈 The problem was that I did not exactly know the syntax for writing the relationshipFilter
within ReadRelationshipsRequest
, but I finally made that work 😅
const readRequest = v1.ReadRelationshipsRequest.create({
relationshipFilter: v1.RelationshipFilter.create({
resourceType: teamReference.objectType,
optionalResourceId: teamReference.objectId,
}),
});
Currently I am a bit stuck when I try to delete certain relationships. Some code for context:
async function performRelationshipDeleteOperation(request) {
return new Promise((resolve, reject) => {
client.deleteRelationships(request, (err, response) => {
if (err) {
console.error("Error in delete operation:", err);
reject(err);
} else {
resolve(response);
}
});
});
}
async function deleteRelationshipsForInactiveEmployees(
teamId,
inactiveEmployeeIds,
) {
const teamReference = defineObjectReference(
"team",
teamId,
);
for (const employeeId of inactiveEmployeeIds) {
const employeeReference = defineObjectReference("employee", employeeId);
const relationshipDelete = {
relationship: v1.Relationship.create({
resource: teamReference,
relation: "member",
subject: v1.SubjectReference.create({
object: employeeReference,
}),
}),
operation: v1.RelationshipUpdate_Operation.DELETE,
};
const deleteRelationshipRequest = {
updates: [relationshipDelete],
};
try {
await performRelationshipDeleteOperation(deleteRelationshipRequest);
console.log(`Deleted relationship for inactive employee: ${employeeId}`);
} catch (error) {
logger.error(error, {
context: "Error deleting relationship for inactive employee",
employeeId: employeeId,
});
}
}
}
I get the following error at await performRelationshipDeleteOperation(deleteRelationshipRequest)
:
Error in delete operation: Error: 13 INTERNAL: Request message serialization failure: Cannot read properties of undefined (reading 'length')
My take on it is that I am not using client.deleteRelationships
correctly 😢
Hi! @alecmerdler Any ideas on what could be wrong with my implementation of deleting relationships?
@MadaPas You can find the type signature for the DeleteRelationships
API here. Similar to ReadRelationships
, it takes a relationshipFilter
. In the code you provided, it looks like you are passing in a v1.Relationship
instead of a filter.
If you can, I highly recommend using TypeScript with this client as it makes it much more obvious what parameters and return types that the client uses. Even if your project isn't using TypeScript, many text editors (like VSCode) should still allow you to jump into the method definitions to validate that you are passing the right arguments.