5 个不稳定版本
0.3.2 | 2024年7月31日 |
---|---|
0.3.1 | 2024年7月31日 |
0.2.2 | 2024年7月19日 |
0.1.0 | 2024年7月12日 |
#1139 在 数据库接口
每月下载量 613
52KB
1K SLoC
spicedb-rust
一个基于官方 gRPC API 构建的 SpiceDB 的有观点客户端,避免了在 Rust 中使用 gRPC 的缺点。
免责声明
API 仍不稳定,可能存在破坏性更改
API
API 提供了所有 gRPC 请求的构建器接口,利用泛型 trait 类型系统减少了部分请求构建的样板代码和潜在的错误/打字错误。
一些最常见的请求直接作为函数暴露在 Client
结构中,例如 lookup_resources
直接到 Vec<R::Id>
或直接到 check_permission
到 bool
。
作为构建器接口的替代,客户端还直接暴露了所有参数一次的方法,如果您打算使用即将推出的 mock
功能,以避免在测试中运行本地的 SpiceDB
实例,建议您这样做。
关于 impl Trait
参数在 SpiceDBClient
上的实现,这些参数都已通过泛型或仅为 String
、&str
删除。这种轻微的 QoL 丢失允许 mockall
构建 MockSpiceDBClient
。
类型系统
此 crate 的类型系统允许定义 Rust 结构体,其 traits 反映了导入到 SpiceDB 中的架构。这减少了在开发过程中键入原始字符串时可能出现的打字错误和其他错误,并使得使用一些编译时检查构建相当复杂的 gRPC 请求变得更容易。
优点
- 永远不会因为为关系或权限传递错误的
String
值而出错 - 永远不会尝试创建不属于您的实体之一的关系
- 通过将您的授权模式集中到 Rust 库 crate 中,轻松地在多个服务间共享您的授权模式
- 从
String 类型自动转换为您的 id 类型,如
u32 或
Uuid
缺点
- 有一些样板代码
我不喜欢类型系统,能否直接使用原始 gRPC API?
可以的。 SpiceDBClient
提供了获取底层 tonic
客户端的方法,而 spicedb
模块导出了所有 protobuf 类型。根据个人经验,这并不有趣。
示例
让我们看看以下 SpiceDB 模式
definition user {}
definition document {
relation reader: user | user:*
relation writer: user
permission read = reader + writer
permission write = writer
}
我们有 2 个实体,User
和 Document
。这是样板代码
struct User;
impl Entity for User {
type Relations = NoRelations;
type Id = Uuid;
fn object_type() -> &'static str {
"user"
}
}
struct MyActor(Uuid);
impl Actor for MyActor {
fn to_subject(&self) -> SubjectReference {
subject_reference_raw(self.0, User::object_type(), None::<String>)
}
}
struct Document;
#[derive(IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum DocumentPermission {
Read,
Write,
}
impl Entity for Document {
type Relations = DocumentRelation;
type Id = String;
fn object_type() -> &'static str {
"document"
}
}
#[derive(IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum DocumentRelation {
Reader,
Writer,
}
impl Resource for Document {
type Permissions = DocumentPermission;
}
注意: 由于
strum
crate 中的IntoStaticStr
宏,现在已经移除了Relations
和Permissions
的样板代码,此 crate 也重新导出了它。
现在的类型系统使得无法检查不存在的权限,或创建不支持实体的关系。
注意: 我不知道是否可以通过类型限制关系的 Subject 部分,我还没有走过这条路,而且我现在还不需要,我会很好奇是否有简单的方法来做这件事。
现在让我们创建一些关系并检查一些权限!
let client = SpiceDBClient::new("https://127.0.0.1:50051".to_owned(), "randomkey")
.await?;
let user_id = Uuid::now_v7();
let relationships = [
relationship_update::<User, Document>(
RelationshipOperation::Touch,
user_id,
None,
"homework",
DocumentRelation::Writer,
),
wildcard_relationship_update::<User, Document>(
RelationshipOperation::Touch,
"manga",
DocumentRelation::Reader,
),
];
let token = client
.create_relationships(relationships, [])
.await
.unwrap();
let actor = MyActor(user_id);
let authorized = client.check_permission_at::<_, Document>(
&actor,
"homework",
DocumentPermission::Write,
token.clone(),
)
.await?;
模拟
启用 mock
功能,以使用由 mockall
生成的客户端。所有公共接口都将按预期工作,但请求构建器接口除外,因为它们没有被模拟,如果您目前正在使用这些接口,您必须针对 SpiceDB 的真实实例进行测试。代码仍然可以编译,但是任何测试到这些代码行的测试都将崩溃。
依赖关系
~6–16MB
~186K SLoC