diff --git a/src/rust/kurisu_api/src/v1.rs b/src/rust/kurisu_api/src/v1.rs
index f038adaa7bfc52573aae139778018e36c35b8959..6cd25131ca7b49a4b2d692fef2a70672926f9602 100644
--- a/src/rust/kurisu_api/src/v1.rs
+++ b/src/rust/kurisu_api/src/v1.rs
@@ -1,8 +1,11 @@
 //! Object rules for the Kurisu's V1 API
 
+use commons::either;
 use serde::Deserialize;
 
-#[derive(Debug, Deserialize)]
+use crate::new_route;
+
+#[derive(Debug, Deserialize, Clone, Copy)]
 pub struct Kara<'a> {
     pub id: i64,
     pub source_name: &'a str,
@@ -33,3 +36,59 @@ impl<'a> Kara<'a> {
         }
     }
 }
+
+#[derive(Debug)]
+pub enum MaybeKaraList<'a> {
+    Empty,
+    Single(Kara<'a>),
+    Multi(Vec<Kara<'a>>),
+}
+
+impl<'a, 'de> Deserialize<'de> for MaybeKaraList<'a>
+where
+    'de: 'a,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        struct Visitor;
+        impl<'de> ::serde::de::Visitor<'de> for Visitor {
+            type Value = MaybeKaraList<'de>;
+
+            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+                write!(formatter, "a kara or a sequence of karas")
+            }
+
+            fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
+            where
+                S: serde::de::SeqAccess<'de>,
+            {
+                let mut ret: Vec<Kara> = Vec::new();
+                while let Ok(Some(kara)) = visitor.next_element() {
+                    ret.push(kara);
+                }
+                Ok(match ret[..] {
+                    [] => MaybeKaraList::Empty,
+                    [single] => MaybeKaraList::Single(single),
+                    _ => MaybeKaraList::Multi(ret),
+                })
+            }
+        }
+
+        deserializer.deserialize_any(Visitor)
+    }
+}
+
+#[derive(Debug, Deserialize, PartialEq, Eq)]
+#[serde(transparent)]
+pub struct KaraDl<'a> {
+    pub content: Vec<u8>,
+
+    #[serde(skip)]
+    _phantom: std::marker::PhantomData<&'a u8>,
+}
+
+new_route! { GetKara      :: "/@" #1          -> MaybeKaraList }
+new_route! { GetKaraPerId :: "/id/@" #1       -> Kara          }
+new_route! { GetKaraDl    :: "/download/@" #1 -> KaraDl        }