Skip to main content

engenho_types/
api.rs

1//! API discovery helpers — `GroupVersion` parsing + path construction.
2//!
3//! Tiny helper layer that turns the typed `GroupVersionKind` /
4//! `GroupVersionResource` from `kind.rs` into the URL path segments
5//! the apiserver router needs.
6
7use crate::kind::{GroupVersionKind, GroupVersionResource, Scope};
8
9/// Construct the REST path for a List/Watch on a resource.
10///
11/// - Core (`group=""`): `/api/v1/{resource}` or
12///   `/api/v1/namespaces/{ns}/{resource}`.
13/// - Non-core: `/apis/{group}/{version}/{resource}` or
14///   `/apis/{group}/{version}/namespaces/{ns}/{resource}`.
15#[must_use]
16pub fn list_path(gvr: GroupVersionResource, scope: Scope, namespace: Option<&str>) -> String {
17    let base = if gvr.group.is_empty() {
18        format!("/api/{}", gvr.version)
19    } else {
20        format!("/apis/{}/{}", gvr.group, gvr.version)
21    };
22    match (scope, namespace) {
23        (Scope::Namespaced, Some(ns)) => format!("{base}/namespaces/{ns}/{}", gvr.resource),
24        (Scope::Namespaced, None) | (Scope::Cluster, _) => format!("{base}/{}", gvr.resource),
25    }
26}
27
28/// Construct the REST path for a single-item GET / PUT / PATCH / DELETE.
29#[must_use]
30pub fn item_path(
31    gvr: GroupVersionResource,
32    scope: Scope,
33    namespace: Option<&str>,
34    name: &str,
35) -> String {
36    format!("{}/{name}", list_path(gvr, scope, namespace))
37}
38
39/// Build the `apiVersion` string from a GVK.
40#[must_use]
41pub fn api_version(gvk: GroupVersionKind) -> String {
42    if gvk.group.is_empty() {
43        gvk.version.to_string()
44    } else {
45        format!("{}/{}", gvk.group, gvk.version)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    const POD_GVR: GroupVersionResource = GroupVersionResource {
54        group: "",
55        version: "v1",
56        resource: "pods",
57    };
58    const DEPLOY_GVR: GroupVersionResource = GroupVersionResource {
59        group: "apps",
60        version: "v1",
61        resource: "deployments",
62    };
63    const POD_GVK: GroupVersionKind = GroupVersionKind {
64        group: "",
65        version: "v1",
66        kind: "Pod",
67    };
68    const DEPLOY_GVK: GroupVersionKind = GroupVersionKind {
69        group: "apps",
70        version: "v1",
71        kind: "Deployment",
72    };
73
74    #[test]
75    fn list_path_core_namespaced() {
76        assert_eq!(
77            list_path(POD_GVR, Scope::Namespaced, Some("default")),
78            "/api/v1/namespaces/default/pods"
79        );
80    }
81
82    #[test]
83    fn list_path_core_cluster() {
84        assert_eq!(
85            list_path(POD_GVR, Scope::Namespaced, None),
86            "/api/v1/pods"
87        );
88    }
89
90    #[test]
91    fn list_path_apps_namespaced() {
92        assert_eq!(
93            list_path(DEPLOY_GVR, Scope::Namespaced, Some("kube-system")),
94            "/apis/apps/v1/namespaces/kube-system/deployments"
95        );
96    }
97
98    #[test]
99    fn item_path_appends_name() {
100        assert_eq!(
101            item_path(POD_GVR, Scope::Namespaced, Some("default"), "my-pod"),
102            "/api/v1/namespaces/default/pods/my-pod"
103        );
104    }
105
106    #[test]
107    fn api_version_core() {
108        assert_eq!(api_version(POD_GVK), "v1");
109    }
110
111    #[test]
112    fn api_version_apps() {
113        assert_eq!(api_version(DEPLOY_GVK), "apps/v1");
114    }
115}