5 个不稳定版本
0.3.1 | 2019年11月17日 |
---|---|
0.2.2 | 2019年11月10日 |
0.2.1 | 2019年11月10日 |
0.2.0 | 2019年11月10日 |
0.1.0 | 2019年11月2日 |
#19 in #json-api
24 每月下载量
用于 rabbithole-endpoint-actix
72KB
1.5K SLoC
rabbithole-rs

兔子洞径直向前,像隧道一样,然后突然向下倾斜,如此突然,爱丽丝甚至没有时间思考如何停下来,就发现自己掉进了一个似乎非常深的井。
-- 刘易斯·卡罗尔的《爱丽丝梦游仙境》
简介
Rabbithole-rs 是一个类型安全的、用户友好的 JSON:API 类型系统,具有易于使用的宏系统,可以帮助您建模数据。
深受 jsonapi-rust 的启发,实际上,所有 tests
中的示例数据都来自这个包。做得好,michiel!
那么什么是 JSON:API 呢?
如果您曾因 JSON 响应的格式与团队成员争论过,那么 JSON:API 可以成为您的反自行车道工具。
通过遵循共享约定,您可以提高生产力,利用通用工具,并专注于最重要的事情:您的应用程序。
当您设计 RESTful API 时,最令人烦恼的问题是 如何设计数据结构,特别是如何 设计错误系统。因此,JSON:API 为像您这样的人设计了一个规范,以指定一些规则来帮助您处理设计问题并解放您的日子!
也许规范很长很无聊,就像读教科书一样,但请相信我,您将从中学到很多东西,就像教科书一样。 :)
那么为什么还需要另一个 JSON:API 包呢?
需要 RSQL 支持
这个包的一个主要原因是我需要支持 RSQL/FIQL,因为我认为它是一个针对复杂查询的良好定义的查询系统。JSON:API 没有提供官方的查询/过滤器解决方案,但我认为 RSQL/FIQL 足够好,可以处理我的项目。
有关 RSQL/FIQL 的更多信息,请参阅
- rsql-rs,我的项目,请查看并给我 Star,谢谢!
- rsql-parser(可能是最好的 RSQL 解析器实现)
- FIQL 规范
类型安全的系统
作为一名Scala程序员,我相信一个设计良好的类型系统可以避免许多问题。我想知道Rust的ADT系统是否能够处理这种复杂性带来的问题。事实上,它处理得很好。
用户友好的宏和建模
作为一名Java开发者,我非常喜欢注解系统。幸运的是,Rust使用proc_macro系统为用户提供“最精确”的体验。
例如,而不是
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Dog {
id: String,
name: String,
age: i32,
main_flea: Flea,
fleas: Vec<Flea>,
}
jsonapi_model!(Dog; "dog"; has one main_flea; has many fleas);
我可以这样建模我的数据结构
#[derive(rbh_derive::EntityDecorator, Serialize, Deserialize, Clone)]
#[entity(type = "dogs")]
pub struct Dog<'a> {
#[entity(id)]
pub id: String,
pub name: String,
#[entity(to_many)]
pub fleas: Vec<Flea>,
#[entity(to_many)]
pub friends: Vec<Dog<'a>>,
#[entity(to_one)]
#[serde(bound(deserialize = "Box<Human<'a>>: Deserialize<'de>"))]
pub master: Box<Human<'a>>,
#[entity(to_one)]
pub best_one: Option<Box<Dog<'a>>>,
}
对我来说,第二种方式更漂亮。
特性
-
基本JSON:API模型系统
-
基本宏系统
-
基本测试
-
查询/过滤API
- 查询/过滤模型
- (部分完成) 现在可以自动查询/过滤了
-
- actix后端
- (可能) Hyper后端
一些问题
带有关系路径的查询不起作用
查看详细问题。
在使用分页查询时缺少额外的meta
和links
字段
在规范中,当使用page
查询时,
meta
对象应该添加一个totalPage
字段links
对象应该添加prev
、next
、first
和last
链接,但是rabbithole
不能自动处理,用户需要通过在Fetching::vec_to_document
中手动实现来添加这些字段。
未来工作
宏系统中的类型检查和错误提示
rabbithole-rs中有许多类型限制。例如
-
[#to_one]
装饰器只能用于类型为rabbithole::entity::Entity
- 或
rabbithole::entity::Entity
的包装类的field
上,其中wrapper
类是以下之一Option<T>
Box<T>
&T
- 另一个包装类内部的,如
Option<Box<T>>
-
#[to_many]
装饰器只能用于具有(所有)以下属性的field
- 迭代器
- 迭代器的内部类型应满足上述限制
- 没有嵌套列表(讨论中)
现在由于Rust缺乏反射,宏现在无法检查类型错误,因此可能需要一些解决方案。
高性能服务器
由于JSON:API的API接口复杂,我认为自己编写所有遵循规范的API接口是一件繁琐且无聊的工作,所以我将为你做这些无聊的事情!
我对这个项目的最终目标
项目的最终目标就像crnk或elide一样,可以基于model
的定义自动生成大量API。在这里,我想展示项目最终会是什么样子。
定义模型
第一步是定义一些API友好的模型。
// This is the derive crate which you can use to generate JSON:API specific traits
extern crate rabbithole_derive as rbh_derive;
#[derive(rbh_derive::EntityDecorator, Serialize, Deserialize, Clone)]
#[entity(type = "people")]
pub struct Human {
#[entity(id)]
pub id_code: Uuid,
pub name: String,
#[entity(to_many)]
pub dogs: Vec<Dog>,
}
#[derive(rbh_derive::EntityDecorator, Serialize, Deserialize, Clone)]
#[entity(type = "dogs")]
pub struct Dog {
#[entity(id)]
pub id: Uuid,
pub name: String,
}
编写自己的DAO
rabbithole
不绑定任何特定的数据库,这意味着你必须编写自己的DAO。
查看rabbithole-endpoint-actix/examples/mock_gen.rs
获取更多详细信息。
Fetching
特质是什么
Fetching
特质是JSON:API中“获取数据”部分的映射,它定义了几个操作
- 获取资源
- 单个资源:
GET /articles/1
- 多个资源:
GET /articles
- 相关资源:
GET /articles/1/author
,可以是单个或多个
- 单个资源:
- 获取关系
- 关系:
GET /articles/1/relationships/comments
- 关系:
- 带有查询参数的获取
- 相关资源的包含(
include
部分) - 稀疏字段集(
fields[TYPE]
部分) - 排序(
sort
部分) - 分页(
page
部分)
- 相关资源的包含(
这就是我们在fetching data
部分需要了解的所有内容。因此,这些操作被抽象为Fenching
特质。
vec_to_document
部分是什么?
如果你想要将一个Vec<SingleEntity>
转换为一个Document
,它会执行许多操作,如排除未包含的资源,保留稀疏字段等等,当然,我可以在后台帮助你(使用Entity::to_document_automatically
)。但为什么只是从数据库提取所有字段并在之后丢弃它们?为什么不直接将它们留在数据库中?所以这就是关键点。如果你不想编写将Vec<SingleEntity>
转换为Document的代码,只需使用Entity::to_document_automatically
,或者,你可以直接从数据库中组装Document
。
...
(其他)部分是什么?
fetch_collection
将被映射为:/<ty>?<query>
fetch_single
将被映射为:/<ty>/<id>?<query>
fetch_relationship
将被映射为:/<ty>/<id>/relationships/<related_field>?<query>
fetch_related
将被映射为:/<ty>/<id>/<related_field>?<query>
type Error
如果可能,将被映射到错误响应中type Item
必须是SingleEntity
依赖项
~10-19MB
~281K SLoC