A SpiceDB client library striving to be as ergonomic as possible.
This library builds upon the official authzed-go library, but tries to expose an interface that guides folks towards optimal performance and correctness.
- ✅ Security-obvious client constructors
- ✅ Defaults to SpiceDB's best compression method
- ✅ Automatic back-off & retry logic
- ✅ Check One/Many/Any/All methods
- ✅ Checks use BulkChecks under the hood
- ✅ Interfaces for Relationships, Objects
- ✅ Flattened Relationship-type with Caveats
- ✅ Transaction-style API for Write
- ✅ Constructors for consistency arguments
- ✅ Callback-style API for Watch and ReadRelationships
- ✅ Atomic and non-atomic Relationship deletion
- 🔜 Keepalives for watch (if necessary)
- ✅ Checks
- ✅ Schema Read/Write
- ✅ Relationship Read/Write/Delete
- 🚧 Import/Export Relationships
- ✅ Watch
- 🔜 Request Debugging
- 🔜 Lookup Resources/Subjects
- 🔜 Reflection APIs
import "github.com/jzelinskie/gochugaru/client"
...
// Various constructors to allocate clients for dev and production environments
// using the best practices.
authz, err := client.NewSystemTLS("spicedb.mycluster.local", presharedKey)
if err != nil {
...
}
import "github.com/jzelinskie/gochugaru/client"
import "github.com/jzelinskie/gochugaru/rel"
...
// Build up a set of relationships to be checked like any other slice.
var founders []Relationship
for _, founder := range []string{"jake", "joey", "jimmy"} {
// There are various constructors for the Relationship type that can
// trade-off allocations for legibility and understandability.
rel, err := rel.FromTriple("company:authzed", "founder", "user:"+founder)
if err != nil {
...
}
founders = append(founders, rel)
}
// Various Check methods can be used to simplify common assertions.
allAreFounders, err := authz.CheckAll(ctx, consistency.MinLatency(), founders...)
if err != nil {
...
} else if !allAreFounders {
...
}
import "github.com/jzelinskie/gochugaru/client"
import "github.com/jzelinskie/gochugaru/rel"
...
// Transactions are built up of preconditions that must or must not exist and
// the set of updates (creates, touches, or deletes) to be applied.
var txn rel.Txn
// The preconditions:
for _, rival := range []string{"joey", "jake"} {
txn.MustNotMatch(rel.MustFromTriple("module:gochugaru", "creator", "user:"+rival).Filter())
}
// The updates:
txn.Touch(rel.MustFromTriple("module:gochugaru", "creator", "user:jimmy"))
txn.Touch(rel.MustFromTriple("module:gochugaru", "maintainer", "sam").
WithCaveat("on_tuesday", map[string]any{"day": "wednesday"}))
writtenAt, err := authz.Write(ctx, txn)
...