Menu
Public repository / master
AkurAI-Framework / crates/collections/src/meta.rs
Latest change 802374bdcc6dcc0421804cba41a30f724cc4b6dc - feat(collections): relation fields with referential checks and ?expand= read-time expansion by Ólafur Búi Ólafsson
//! The `/api/_meta` manifest builder.
//!
//! [`meta`] turns a set of [`Collection`]s into a JSON [`Value`] describing each
//! collection, its fields, and the REST endpoints the framework exposes for it.
//! The CLI merges this into the framework-wide `/api/_meta` document.
use akurai_json::Value;
use crate::schema::Collection;
/// Build the manifest for a set of collections.
///
/// Shape:
///
/// ```json
/// {
/// "collections": [
/// {
/// "name": "posts",
/// "fields": [
/// { "name": "title", "type": "text", "required": true, "embed": false }
/// ],
/// "endpoints": {
/// "list": "GET /api/collections/posts/records",
/// "create": "POST /api/collections/posts/records",
/// "get": "GET /api/collections/posts/records/<id>",
/// "update": "PATCH /api/collections/posts/records/<id>",
/// "delete": "DELETE /api/collections/posts/records/<id>",
/// "search": "GET /api/collections/posts/records?search=<query>"
/// }
/// }
/// ]
/// }
/// ```
pub fn meta(colls: &[Collection]) -> Value {
let items = colls.iter().map(collection_meta).collect();
Value::Object(vec![("collections".into(), Value::Array(items))])
}
fn collection_meta(coll: &Collection) -> Value {
let fields = coll
.fields
.iter()
.map(|f| {
let mut entry = vec![
("name".into(), Value::Str(f.name.clone())),
("type".into(), Value::Str(f.kind.as_str().into())),
("required".into(), Value::Bool(f.required)),
("embed".into(), Value::Bool(f.embed)),
];
// A relation field also advertises its target collection.
if let Some(target) = f.kind.relation_target() {
entry.push(("collection".into(), Value::Str(target.to_string())));
}
Value::Object(entry)
})
.collect();
let base = format!("/api/collections/{}/records", coll.name);
let endpoints = Value::Object(vec![
("list".into(), Value::Str(format!("GET {base}"))),
("create".into(), Value::Str(format!("POST {base}"))),
("get".into(), Value::Str(format!("GET {base}/<id>"))),
("update".into(), Value::Str(format!("PATCH {base}/<id>"))),
("delete".into(), Value::Str(format!("DELETE {base}/<id>"))),
(
"search".into(),
Value::Str(format!("GET {base}?search=<query>")),
),
]);
Value::Object(vec![
("name".into(), Value::Str(coll.name.clone())),
("fields".into(), Value::Array(fields)),
("endpoints".into(), endpoints),
])
}