Swagger/OpenAPI генерация для Rust: Utoipa — современный инструмент для автоматической документации
При разработке веб-приложений на Rust документация API — не роскошь, а необходимость. Библиотека Utoipa (сокращение от "Utopia") предоставляет мощный и элегантный способ генерации OpenAPI спецификаций прямо из кода. Она интегрируется с популярными веб-фреймворками, такими как actix-web, axum, rocket и warp, и позволяет описывать эндпоинты, схемы данных и параметры с помощью атрибутов и макросов.
Основные возможности Utoipa
- Автоматическая генерация OpenAPI 3.0/3.1 — без ручного написания YAML/JSON.
- Поддержка множества фреймворков — actix-web, axum, rocket, warp.
- Интеграция с Swagger UI — встроенный компонент для визуализации документации.
- Глубокое описание схем — поддержка вложенных структур, перечислений, опциональных полей.
- Макросы для быстрого описания —
#[utoipa::path],#[openapi]. - Валидация спецификации — проверка корректности сгенерированного документа.
Установка и настройка
Добавьте зависимости в Cargo.toml. Для примера выберем фреймворк actix-web:
[dependencies]
utoipa = "4"
utoipa-swagger-ui = { version = "4", features = ["actix-web"] }
actix-web = "4"
serde = { version = "1", features = ["derive"] }
Базовый пример: создание API с документацией
Рассмотрим простой CRUD для сущности "Пользователь". Начнём с определения модели данных:
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Serialize, Deserialize, ToSchema)]
pub struct User {
#[schema(example = "1")]
pub id: i32,
#[schema(example = "john_doe")]
pub username: String,
#[schema(example = "john@example.com")]
pub email: String,
}
Теперь опишем эндпоинт получения списка пользователей с помощью макроса #[utoipa::path]:
use actix_web::{get, web, HttpResponse, Responder};
use utoipa::OpenApi;
#[utoipa::path(
get,
path = "/users",
responses(
(status = 200, description = "Список пользователей", body = Vec<User>)
)
)]
#[get("/users")]
async fn get_users() -> impl Responder {
let users = vec![
User { id: 1, username: "alice".into(), email: "alice@example.com".into() },
User { id: 2, username: "bob".into(), email: "bob@example.com".into() },
];
HttpResponse::Ok().json(users)
}
Сборка OpenAPI документа и Swagger UI
Создаём структуру для описания всего API:
#[derive(OpenApi)]
#[openapi(
paths(get_users),
components(schemas(User))
)]
pub struct ApiDoc;
// В main функции настраиваем Swagger UI
use utoipa_swagger_ui::SwaggerUi;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::App;
HttpServer::new(|| {
App::new()
.service(get_users)
.service(
SwaggerUi::new("/swagger-ui/{_:.*}")
.url("/api-docs/openapi.json", ApiDoc::openapi())
)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
После запуска приложения документация будет доступна по адресу http://localhost:8080/swagger-ui/.
Продвинутые возможности: вложенные схемы и параметры
Utoipa поддерживает сложные типы данных. Например, добавим поле с вложенной структурой:
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Address {
#[schema(example = "г. Москва")]
pub city: String,
#[schema(example = "ул. Ленина, д. 1")]
pub street: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct UserWithAddress {
pub id: i32,
pub username: String,
pub address: Address, // вложенная схема
}
Также можно описывать параметры пути и query-параметры:
#[utoipa::path(
get,
path = "/users/{id}",
params(
("id" = i32, Path, description = "Идентификатор пользователя