🦀
Rust и магия динамики: как создать Python‑подобный API с помощью SerdeВ новой статье *Ohad Dravid* демонстрирует, как в языке Rust можно добиться удобства динамического доступа к данным — в духе Python — но
без потери строгой типизации и производительности. Всё это — с помощью мощной библиотеки
serde.
📌 Статья: *“A Rust API Inspired by Python, Powered by Serde”*
🔗 [
ohadravid.github.io/posts/2025-05-serde-reflect](https://ohadravid.github.io/posts/2025-05-serde-reflect/)
🔍 Проблема
Python позволяет обращаться к произвольным полям объектов, например при работе с WMI:
for fan in c.Win32_Fan():
print(fan.Name, fan.DesiredSpeed)
А вот Rust требует ручной работы: если вы хотите получить поле объекта по имени — нужно писать
get_attr, делать
match, проверять типы и всё это каждый раз.
🙄 Это:
- многословно,
- подвержено ошибкам,
- неудобно для пользователя API.
🎯 Цель
Сделать API на Rust, который позволял бы:
1. Писать простой, декларативный код
2. Избегать ручной сериализации и проверки типов
3. Получать строго типизированные структуры из «сырых» данных
И всё это —
без хаков и макросов, а с помощью
serde и аккуратной архитектуры.
⚙️ Как это реализовано
Охад реализует три версии API:
🛠 1.
raw_api.rs — примитивный уровень
pub enum Value { Bool(bool), I1(i8), UI8(u64), String(String), Object(Object) }
impl Object {
pub fn get_attr(&self, name: &str) -> Value { /* ... */ }
}
Каждый вызов требует ручного
match, приведения типов, извлечения значений.
✨ 2.
v1_api.rs — пользователь сам описывает структуру + ручная десериализация
Пользователь описывает
struct, и сам реализует для него трейт, чтобы распаковать поля.
🚀 3.
v2_api.rs — Serde‑магию включено
Теперь
query() возвращает
Vec<T>:
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Fan {
name: String,
active_cooling: bool,
desired_speed: u64,
}
let res: Vec<Fan> = query();
for fan in res {
if fan.active_cooling {
println!("Fan `{}` is running at {} RPM", fan.name, fan.desired_speed);
}
}
Теперь:
- никакой ручной сериализации
- никаких
match - всё строго типизировано и работает с минимальными затратами
🧠 Как это работает под капотом
Проект использует:
•
serde::Deserialize • внутренний модуль
meta.rs, который:
- извлекает названия полей и их типы
- генерирует SQL‑подобный запрос под структуру
- использует эти поля для сопоставления данных
API получается универсальным: любую структуру, которая реализует
Deserialize, можно использовать как результат запроса.
📈 Почему это важно
✅ Приближает Rust к удобству Python, сохраняя безопасность
✅ Минимизирует дублирование кода
✅ Даёт мощный, типобезопасный интерфейс над динамическими структурами
✅ Применимо к WMI, COM, JSON API, SQL‑слоям и множеству других задач
🔭 Возможности расширения
- Генерация запросов по структурам (`SELECT ... FROM ... WHERE ...`)
- Интеграция с внешними API (WMI, COM)
- Расширение в сторону
serde-reflection для полного introspection
- Создание DSL поверх API для ещё более лаконичного запроса данных
📚 Заключение
Rust и
serde — это не только про производительность и безопасность, но и про
удобный API, если правильно подойти к задаче. Этот проект показывает, как можно сделать
гибкий, декларативный, типобезопасный интерфейс для работы с данными — без костылей и магии рантайма.
Если ты когда-либо хотел писать на Rust как на Python — но без ущерба для надёжности — это один из лучших паттернов, который стоит изучить.
🔗 Читай подробнее: [
ohadravid.github.io/posts/2025-05-serde-reflect](https://ohadravid.github.io/posts/2025-05-serde-reflect/)\