authzed / spicedb

Open Source, Google Zanzibar-inspired database for scalably storing and querying fine-grained authorization data
https://authzed.com/docs
Apache License 2.0
5.07k stars 272 forks source link

Add an API to exactly "Set" a relation #2033

Open mateenkasim opened 2 months ago

mateenkasim commented 2 months ago

Problem Statement

TLDR

I propose creating a "Set" API that receives a resource type, resource ID, and relation name as well as a subject or set of subjects, and it atomically does the following:

Abstractly, this allows for atomically setting a relationship to an exact value (or set of values) without requiring the user to read the old value, construct preconditions for avoiding race conditions, or construct explicit DELETE operations.

Description

It's established that all SpiceDB relations are essentially many-to-many relations. Consider this schema:

definition student {}

definition class {
    relation enrolled: student
}

In this case, the many-to-many relation enrolled is appropriate; a class can have many enrolled students, and a student can be enrolled in many classes. Now, consider this schema:

definition folder {}

definition file {
    relation parent: folder
}

In this case, the many-to-many relation is inappropriate; a folder can have many files, but a file can have exactly one parent folder. If a user wants file.parent to be a many-to-one relation, this must be enforced at the application level, not the DB level.

Users of SpiceDB will always want to model one-to-one, many-to-one, and many-to-many relations, and I believe SpiceDB users are duplicating a lot of work to enforce these invariants at the application level. To make this easier without extending the schema, SpiceDB could expose an atomic "Set" operation that exactly defines a relation.

I consider two scenarios:

This is quite a lot of work to enforce an otherwise common DB paradigm. It would be alleviated if SpiceDB had a semantic to exactly "set" the relationship, internally handling the deletion of all previous values without requiring the user to know what those previous values were.

Solution Brainstorm

I'm not completely sure what the Set API would look like. I offer two options here, one for each scenario mentioned above.

// Clears all tuples that match the RelationshipHead // Writes new tuples using the RelationshipHead as resource/relation and the given subjects as subject message SetRelationshipRequest { RelationshipHead relationship_head = 1; repeated SubjectReference subjects = 2; }



Of course, my goal is the capability this operation provides, and I am not attached to the APIs I proposed. Happy to hear anyone else's thoughts on the matter or other solutions if they come up. Thanks for all the work y'all do on SpiceDB!
tstirrat15 commented 2 months ago

One piece of context: for this use case, SpiceDB is the primary store of this data. I think in other contexts these sorts of invariants would be enforced by the API/datastore that was the primary store of the data prior to replication into SpiceDB.