fraiseql_cli/config/toml_schema/rest/mod.rs
1//! REST transport TOML configuration.
2
3use fraiseql_core::schema::{DeleteResponse, RestConfig};
4use serde::{Deserialize, Serialize};
5
6/// REST transport configuration parsed from the `[rest]` TOML section.
7///
8/// All fields have defaults matching `RestConfig::default()` in `fraiseql-core`.
9/// When `enabled` is `false` (the default), the REST transport is not mounted.
10#[derive(Debug, Clone, Deserialize, Serialize)]
11#[serde(default)]
12pub struct RestTomlConfig {
13 /// Whether the REST transport is enabled.
14 pub enabled: bool,
15 /// Base URL path for REST endpoints.
16 pub path: String,
17 /// Maximum rows per page (clamps `?limit=`).
18 pub max_page_size: u64,
19 /// Default page size when no `?limit=` is specified.
20 pub default_page_size: u64,
21 /// Batch size for NDJSON streaming responses.
22 pub ndjson_batch_size: u64,
23 /// Maximum affected rows for bulk PATCH/DELETE.
24 pub max_bulk_affected: u64,
25 /// Maximum byte length for `?filter=` JSON values.
26 pub max_filter_bytes: u64,
27 /// How DELETE endpoints report success: `"no_content"` (default) or `"entity"`.
28 pub delete_response: DeleteResponseToml,
29 /// Default result cache TTL in seconds (0 = no caching).
30 pub default_cache_ttl: u64,
31 /// CDN `s-maxage` value in seconds (`None` = omit).
32 pub cdn_max_age: Option<u64>,
33 /// Whether REST endpoints require authentication by default.
34 pub require_auth: bool,
35 /// SSE heartbeat interval in seconds.
36 pub sse_heartbeat_seconds: u64,
37 /// Maximum depth for resource embedding (`?select=posts(comments)`).
38 pub max_embedding_depth: u32,
39 /// Allowlist of type names to expose as REST resources (empty = all).
40 pub include: Vec<String>,
41 /// Denylist of type names to exclude from REST resources.
42 pub exclude: Vec<String>,
43 /// Whether to enable `ETag` / `If-None-Match` conditional response support.
44 pub etag: bool,
45 /// TTL in seconds for idempotency key deduplication.
46 pub idempotency_ttl_seconds: u64,
47}
48
49/// DELETE response mode for TOML configuration.
50///
51/// Uses lowercase serde names for TOML ergonomics.
52#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
53#[serde(rename_all = "snake_case")]
54pub enum DeleteResponseToml {
55 /// Return `204 No Content`.
56 #[default]
57 NoContent,
58 /// Return `200` with the deleted entity in the body.
59 Entity,
60}
61
62impl Default for RestTomlConfig {
63 fn default() -> Self {
64 Self {
65 enabled: false,
66 path: "/rest/v1".to_string(),
67 max_page_size: 1_000,
68 default_page_size: 100,
69 ndjson_batch_size: 500,
70 max_bulk_affected: 10_000,
71 max_filter_bytes: 4_096,
72 delete_response: DeleteResponseToml::NoContent,
73 default_cache_ttl: 0,
74 cdn_max_age: None,
75 require_auth: false,
76 sse_heartbeat_seconds: 30,
77 max_embedding_depth: 3,
78 include: Vec::new(),
79 exclude: Vec::new(),
80 etag: true,
81 idempotency_ttl_seconds: 300,
82 }
83 }
84}
85
86impl From<DeleteResponseToml> for DeleteResponse {
87 fn from(toml: DeleteResponseToml) -> Self {
88 match toml {
89 DeleteResponseToml::NoContent => Self::NoContent,
90 DeleteResponseToml::Entity => Self::Entity,
91 }
92 }
93}
94
95impl From<RestTomlConfig> for RestConfig {
96 fn from(toml: RestTomlConfig) -> Self {
97 Self {
98 enabled: toml.enabled,
99 path: toml.path,
100 max_page_size: toml.max_page_size,
101 default_page_size: toml.default_page_size,
102 ndjson_batch_size: toml.ndjson_batch_size,
103 max_bulk_affected: toml.max_bulk_affected,
104 max_filter_bytes: toml.max_filter_bytes,
105 delete_response: toml.delete_response.into(),
106 default_cache_ttl: toml.default_cache_ttl,
107 cdn_max_age: toml.cdn_max_age,
108 require_auth: toml.require_auth,
109 sse_heartbeat_seconds: toml.sse_heartbeat_seconds,
110 max_embedding_depth: toml.max_embedding_depth,
111 include: toml.include,
112 exclude: toml.exclude,
113 etag: toml.etag,
114 idempotency_ttl_seconds: toml.idempotency_ttl_seconds,
115 }
116 }
117}
118
119#[cfg(test)]
120#[allow(clippy::unwrap_used)] // Reason: test code, panics are acceptable
121mod tests;