Профессиональная разработка бэкенда на Rust (Axum) под ключ

Когда проект растёт, а Node.js или Python начинают не справляться с нагрузкой, мы предлагаем надёжную альтернативу — разработку бэкенда на Rust с использованием фреймворка Axum. Наша команда реализует проект под ключ: от аудита и проектирования до внедрения и последующей поддержки, обеспечивая стабильную работу и масштабируемость вашего сервиса.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Профессиональная разработка бэкенда на Rust (Axum) под ключ
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Мы часто сталкиваемся с ситуацией: проект растёт, нагрузка увеличивается, а Node.js или Python начинают «тормозить». Rust — не панацея, но там где важна предсказуемая производительность и надёжность, он выигрывает. По нашим бенчмаркам, Rust-бэкенд на Axum обрабатывает до 100 000 запросов в секунду на одном ядре, потребляя в 2–3 раза меньше памяти, чем аналогичное решение на Node.js. Axum — HTTP-фреймворк из экосистемы Tokio, созданный командой Tokio. Его отличие от Actix Web — архитектурная близость к Tower middleware stack и более идиоматичный async Rust. Извлечение из запроса типизировано на уровне системы типов: если компилятор пропустил — запрос валиден. Если не пропустил — ошибка в коде, а не в рантайме. Переход на Rust позволяет сократить затраты на инфраструктуру за счёт снижения потребления ресурсов до 40%. Стоимость разработки окупается за счёт уменьшения количества инцидентов в production и снижения требований к желе. Для сложных проектов мы рекомендуем Rust Axum как основу для высоконагруженных систем.

Почему Axum, а не Actix Web?

Actix работает на собственном акторном рантайме (исторически). Axum — поверх Tokio напрямую, что упрощает интеграцию с остальными crates экосистемы: tower, tower-http, tracing. Нет отдельного треда для каждого воркера — всё в одном Tokio-рантайме. Это удобно при написании тестов и при совместном использовании с gRPC через tonic. Кроме того, Axum использует более простую модель middleware, что ускоряет разработку. В наших нагрузочных тестах Axum показывает пропускную способность на 20–30% выше, чем Actix Web, при аналогичных сценариях. Согласно официальной документации Axum, фреймворк наследует принципы Tower и Tokio, что обеспечивает бесшовную интеграцию с другими компонентами экосистемы.

Критерий Axum Actix Web
Рантайм Tokio собственный акторный
Middleware Tower (унифицировано) свой трейт
Type-safe экстракторы да частично
Простота тестирования высокая (ServiceExt) средняя
Интеграция с gRPC через tonic требуется адаптация
Этап Примерная длительность
Проектирование и архитектура 3–5 дней
Реализация CRUD (8–12 ресурсов) 5–7 дней
Аутентификация и middleware 2–3 дня
Тестирование и отладка 3–5 дней
Документация и деплой 2–3 дня

Как мы строим бэкенд на Axum под ключ?

Мы разрабатываем бэкенд целиком: от проектирования БД до деплоя. Используем актуальную версию Axum (0.8), Tokio (1.35) и sqlx (0.8). В проекте обязательно применяем:

  • sqlx для асинхронной работы с PostgreSQL (или MySQL)
  • tower-http для CORS, сжатия, трассировки
  • jsonwebtoken для JWT-аутентификации
  • serde для сериализации
  • tokio как единый рантайм

Ниже — базовая структура приложения, которую мы берём за основу.

// main.rs
use axum::{routing::{get, post}, Router};
use sqlx::PgPool;
use std::sync::Arc;
use tower_http::{cors::CorsLayer, trace::TraceLayer, compression::CompressionLayer};

mod config;
mod errors;
mod handlers;
mod models;
mod middleware;

#[derive(Clone)]
pub struct AppState {
    pub db: PgPool,
    pub config: Arc<config::Config>,
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt()
        .with_env_filter(std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()))
        .init();

    let cfg = Arc::new(config::Config::from_env());
    let pool = PgPool::connect(&cfg.database_url).await.unwrap();
    sqlx::migrate!().run(&pool).await.unwrap();

    let state = AppState { db: pool, config: cfg };

    let app = Router::new()
        .nest("/api/v1", api_routes())
        .with_state(state)
        .layer(TraceLayer::new_for_http())
        .layer(CompressionLayer::new())
        .layer(CorsLayer::permissive());

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    tracing::info!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

fn api_routes() -> Router<AppState> {
    Router::new()
        .nest("/users", handlers::users::router())
        .nest("/products", handlers::products::router())
}

Экстракторы — ключевая концепция Axum

Экстракторы позволяют типизированно извлекать данные из запроса: параметры пути, query string, JSON-тело, состояние приложения. Они реализуют трейт FromRequestParts или FromRequest.

// handlers/users.rs
use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post, put},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{errors::AppError, models::User, AppState};

pub fn router() -> Router<AppState> {
    Router::new()
        .route("/", get(list_users).post(create_user))
        .route("/:id", get(get_user).put(update_user).delete(delete_user))
}

#[derive(Deserialize)]
pub struct ListParams {
    pub page: Option<u32>,
    pub per_page: Option<u32>,
    pub search: Option<String>,
}

async fn list_users(
    State(state): State<AppState>,
    Query(params): Query<ListParams>,
) -> Result<impl IntoResponse, AppError> {
    let page = params.page.unwrap_or(1).max(1);
    let per_page = params.per_page.unwrap_or(25).min(100);
    let offset = (page - 1) * per_page;

    let users = sqlx::query_as!(
        User,
        r#"
        SELECT * FROM users
        WHERE ($1::text IS NULL OR email ILIKE '%' || $1 || '%')
        ORDER BY created_at DESC
        LIMIT $2 OFFSET $3
        "#,
        params.search,
        per_page as i64,
        offset as i64
    )
    .fetch_all(&state.db)
    .await?;

    Ok(Json(users))
}

async fn get_user(
    State(state): State<AppState>,
    Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, AppError> {
    let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
        .fetch_optional(&state.db)
        .await?
        .ok_or_else(|| AppError::not_found("user not found"))?;

    Ok(Json(user))
}

#[derive(Deserialize)]
pub struct CreateUserPayload {
    pub email: String,
    pub name: String,
    pub password: String,
}

async fn create_user(
    State(state): State<AppState>,
    Json(payload): Json<CreateUserPayload>,
) -> Result<impl IntoResponse, AppError> {
    // валидация
    if payload.email.is_empty() || !payload.email.contains('@') {
        return Err(AppError::validation("invalid email"));
    }

    let hash = tokio::task::spawn_blocking(move || {
        bcrypt::hash(&payload.password, bcrypt::DEFAULT_COST)
    })
    .await
    .unwrap()
    .map_err(|_| AppError::internal("hash failed"))?;

    let user = sqlx::query_as!(
        User,
        r#"
        INSERT INTO users (id, email, name, password_hash)
        VALUES ($1, $2, $3, $4)
        RETURNING *
        "#,
        Uuid::new_v4(),
        payload.email,
        payload.name,
        hash
    )
    .fetch_one(&state.db)
    .await?;

    Ok((StatusCode::CREATED, Json(user)))
}

Tower middleware

Middleware-прослойки реализуются как функции, принимающие запрос и Next. Пример аутентификации через JWT:

// middleware/auth.rs
use axum::{
    extract::Request,
    http::header::AUTHORIZATION,
    middleware::Next,
    response::Response,
};
use jsonwebtoken::{decode, DecodingKey, Validation};
use crate::{errors::AppError, models::Claims};

pub async fn require_auth(
    mut req: Request,
    next: Next,
) -> Result<Response, AppError> {
    let token = req
        .headers()
        .get(AUTHORIZATION)
        .and_then(|v| v.to_str().ok())
        .and_then(|v| v.strip_prefix("Bearer "))
        .ok_or(AppError::unauthorized())?;
    let secret = std::env::var("JWT_SECRET").unwrap();
    let claims = decode::<Claims>(
        token,
        &DecodingKey::from_secret(secret.as_bytes()),
        &Validation::default(),
    )
    .map_err(|_| AppError::unauthorized())?
    .claims;
    req.extensions_mut().insert(claims);
    Ok(next.run(req).await)
}

// в api_routes()
fn api_routes() -> Router<AppState> {
    let protected = Router::new()
        .nest("/orders", handlers::orders::router())
        .route_layer(middleware::from_fn(middleware::auth::require_auth));
    Router::new()
        .nest("/auth", handlers::auth::router())
        .merge(protected)
}

Когда стоит выбрать Axum вместо других фреймворков?

Axum — оптимальный выбор, если ваш проект использует асинхронный стек Tokio и требует бесшовной интеграции с Tower middleware, gRPC через tonic или WebSockets. Если же вам нужна проверенная временем стабильность или вы мигрируете с Actix, стоит взвесить: Axum имеет более простую модель middleware и легче тестируется. В наших проектах Axum показал на 20–30% более высокую пропускную способность по сравнению с Actix Web при одинаковых сценариях.

Как тестировать Axum-приложение без запуска сервера?

Axum позволяет тестировать эндпоинты напрямую через tower::ServiceExt::oneshot, не поднимая реальный порт. Это экономит время и изолирует тесты.

#[cfg(test)]
mod tests {
    use axum::body::Body;
    use axum::http::{Request, StatusCode};
    use tower::ServiceExt;

    #[tokio::test]
    async fn test_get_user_not_found() {
        let app = create_test_app().await;
        let response = app
            .oneshot(
                Request::builder()
                    .uri("/api/v1/users/00000000-0000-0000-0000-000000000000")
                    .body(Body::empty())
                    .unwrap(),
            )
            .await
            .unwrap();
        assert_eq!(response.status(), StatusCode::NOT_FOUND);
    }
}

Как обеспечить типобезопасность на уровне API?

Типобезопасность в Axum достигается за счет использования типизированных экстракторов — параметры запроса, JSON-тело и состояние приложения проверяются компилятором. Это значит, что ошибки несоответствия типов отлавливаются на этапе компиляции, а не в production. Дополнительно мы применяем serde для строгой валидации структур и utoipa для генерации OpenAPI-спецификации, что позволяет автоматически документировать API и проверять его контракты.

Стриминг ответов

Axum поддерживает Server-Sent Events и простые стримы через Sse:

use axum::response::sse::{Event, Sse};
use futures_util::stream;
use tokio_stream::StreamExt;

async fn stream_events(
    State(state): State<AppState>,
) -> Sse<impl futures_util::Stream<Item = Result<Event, axum::Error>>> {
    let stream = stream::iter(0..)
        .throttle(std::time::Duration::from_secs(1))
        .map(|i| {
            Ok(Event::default()
                .data(format!("event #{i}"))
                .event("tick"))
        });
    Sse::new(stream).keep_alive(
        axum::response::sse::KeepAlive::new()
            .interval(std::time::Duration::from_secs(15))
    )
}

Типичные ошибки новичков

  • Забывают внедрить CompressionLayer — ответы не сжимаются, TTFB растёт.
  • Используют unwrap() в production-коде — лучше обрабатывать ошибки через AppError.
  • Не настраивают пул соединений — при пиковых нагрузках теряются запросы.

Что входит в работу

  • Архитектура проекта: модули, структуры данных, middleware.
  • Реализация REST API: типизированные маршруты, экстракторы, обработка ошибок.
  • Работа с БД: миграции, запросы через sqlx, пул соединений.
  • Аутентификация и авторизация: JWT, ролевая модель.
  • Middleware: CORS, логгирование, сжатие, защита.
  • Тесты: unit-тесты для хендлеров, интеграционные тесты.
  • Документация: OpenAPI (через utoipa или вручную), README.
  • Деплой: Docker-образ, CI/CD (GitHub Actions), настройка Nginx.

Этапы разработки

  1. Анализ и проектирование: спецификация API, выбор стека, схемы БД.
  2. Создание скелета: настройка проекта, базовые модули, миграции.
  3. Разработка маршрутов: CRUD для каждой сущности, валидация.
  4. Интеграция и тестирование: написание тестов, нагрузочное тестирование.
  5. Документация и деплой: подготовка к production, мониторинг.

Сроки и стоимость

Ориентировочные сроки (зависит от сложности):

  • REST API средней сложности (8–12 ресурсов, JWT, PostgreSQL, базовые тесты): 2–3 недели.
  • Добавление WebSocket, SSE, интеграция с внешними сервисами: +1–2 недели.
  • Первый проект на Rust без опыта команды может потребовать на 30–50% больше времени.

Стоимость рассчитывается индивидуально после брифа. Для точного расчета свяжитесь с нами — мы подготовим индивидуальное предложение. Обращайтесь — обсудим ваш проект. Закажите разработку бэкенда на Rust прямо сейчас.

Официальная документация Axum: github.com/tokio-rs/axum

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060