Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples for reading relationships in the node client #79

Open
MadaPas opened this issue Nov 15, 2023 · 7 comments
Open

Add examples for reading relationships in the node client #79

MadaPas opened this issue Nov 15, 2023 · 7 comments
Labels
hint/good first issue Someone new could handle this

Comments

@MadaPas
Copy link

MadaPas commented Nov 15, 2023

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 the v1.ObjectReference.create method.
  • Creating a ReadRelationshipsRequest specifying details about the relationship to be read. It includes the ObjectReference and sets the relation to member
  • gRPC: Invoking client.readRelationships method with the defined readRelationshipsRequest.

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.

@brentpi
Copy link

brentpi commented Nov 27, 2023

@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

@MadaPas
Copy link
Author

MadaPas commented Dec 19, 2023

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?

@alecmerdler
Copy link
Contributor

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.

@alecmerdler
Copy link
Contributor

@MadaPas Are you still having trouble with the ReadRelationships API?

@MadaPas
Copy link
Author

MadaPas commented Jan 19, 2024

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 😢

@MadaPas
Copy link
Author

MadaPas commented Jan 24, 2024

Hi!
@alecmerdler Any ideas on what could be wrong with my implementation of deleting relationships?

@alecmerdler
Copy link
Contributor

@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.

@samkim samkim added the hint/good first issue Someone new could handle this label Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hint/good first issue Someone new could handle this
Projects
None yet
Development

No branches or pull requests

4 participants