Професійна розробка бекенду на Rust (Axum) під ключ

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

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

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

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    956
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    947

Ми часто стикаємося з ситуацією: проєкт зростає, навантаження збільшується, а Node.js або Python починають «гальмувати». Rust — не панацея, але там де важлива передбачувана продуктивність і надійність, він виграє. За нашими бенчмарками, Rust-бекенд на Axum обробляє до 100 000 запитів на секунду на одному ядрі, споживаючи в 2–3 рази менше пам'яті, ніж аналогічне рішення на Node.js. Час відповіді — менше 10 мс, пропускна здатність — понад 50 000 RPS на одному вузлі. Axum — HTTP-фреймворк з екосистеми Tokio, створений командою Tokio. Його відмінність від Actix Web — архітектурна близькість до Tower middleware stack та більш ідіоматичний async Rust. Витяг із запиту типізований на рівні системи типів: якщо компілятор пропустив — запит валідний. Якщо не пропустив — помилка в коді, а не в рантаймі. Перехід на Rust дозволяє скоротити витрати на інфраструктуру за рахунок зниження споживання ресурсів до 40%. Вартість розробки окупається за рахунок зменшення кількості інцидентів у production та зниження вимог до заліза. Для складних проєктів ми рекомендуємо Rust Axum як основу для високонавантажених систем.

Ми маємо понад 5 років досвіду розробки на Rust та виконали 20+ проєктів. Надаємо гарантію на бекенд до 6 місяців. Створюємо продуктивний Rust веб-сервер. Використовуємо типобезпечність Rust для надійності.

Чому 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())
}

Ключові концепції: екстрактори та middleware

Екстрактори дозволяють типізовано витягувати дані із запиту: параметри шляху, 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)))
}

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 — оптимальний вибір, якщо ваш проєкт використовує асинхронний стек Tokio і вимагає безшовної інтеграції з Tower middleware, gRPC через tonic або WebSockets. Якщо ж вам потрібна перевірена часом стабільність або ви мігруєте з Actix, варто зважити: Axum має простішу модель middleware і легше тестується. У наших проєктах Axum показав на 20–30% вищу пропускну здатність порівняно з Actix Web при однакових сценаріях.

Тестувати 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 та перевіряти його контракти. Кожен ендпоінт має автоматично згенеровану OpenAPI специфікацію, інтегрований Prometheus моніторинг та логи через OpenTelemetry.

Стримінг та типові помилки

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% більше часу.

Орієнтовна вартість: від $3 000 для простого API до $15 000 для складних систем з WebSocket та мікросервісами. Для точного розрахунку зв'яжіться з нами — ми підготуємо індивідуальну пропозицію. Звертайтеся — обговоримо ваш проєкт. Замовте розробку бекенду на Rust прямо зараз.

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

Послуги бекенд-розробки: production-grade надійність

На production-сервері о 3:14 ночі черга Laravel Jobs перестала оброблятися — 40 000 необроблених завдань у Redis. Причина: worker упав через memory leak у статичній змінній Eloquent observer, supervisor не перезапустив через misconfigured stopwaitsecs. Ми розбирали такий інцидент на проекті з 500 RPS: діагностика 4 години, фікс — 20 хвилин. Щоб ви не втрачали гроші, пропонуємо послуги бекенд-розробки з акцентом на production-grade надійність — 10+ років досвіду, 50+ проектів, 5 років на ринку. Оцінимо ваш проект за 2 дні.

Які проблеми вирішуємо

N+1 запити: головний вбивця швидкості

N+1 — найпоширеніша причина повільних сторінок у Laravel-додатках. Стандартна історія: сторінка працювала нормально на dev з 10 записами, на production з 10 000 — 8-секундне завантаження.

Laravel Debugbar у dev-оточенні показує кількість запитів. Більше 20 — сигнал для audit.

Model::preventLazyLoading(! app()->isProduction());

Telescope для профілювання: логує всі запити, jobs, mail, notifications з деталізацією. Після впровадження eager loading час завантаження сторінки падає з 8 с до 0.3 с — у 27 разів.

Memory leak у статичних змінних

У Laravel Octane або Swoole додаток тримається в пам’яті між запитами. Статичні змінні не скидаються — призводять до неконтрольованого росту пам’яті. Використовуємо defer-функції та контейнерні біндинги для коректного скидання стану.

Неправильний connection pool

Rails, Laravel, Django відкривають нове з'єднання PostgreSQL на кожен PHP/Python процес. 100 воркерів — 100 з'єднань. PostgreSQL деградує від 200+ активних з'єднань через overhead на управління.

PgBouncer у transaction pooling: 1000 воркерів → 20–50 реальних з'єднань. Це знижує latency на 40% та зменшує витрати на хостинг на 30% — при середній вартості хостингу $2,000/міс економить $600/міс. GIN-індекс для JSONB до 100 разів швидший за B-tree при пошуку.

Як Octane справляється з високим навантаженням?

Laravel Octane (RoadRunner або Swoole) прибирає overhead bootstrap на кожен HTTP-запит. Приріст: 3–8x на синтетичних бенчмарках, 2–4x на реальних додатках. Важливо: не зберігати стан у статичних змінних — застосовуємо це на проектах >1000 RPS.

Як PostgreSQL допомагає уникнути повільних запитів?

Використовуємо composite indexes для WHERE + ORDER BY, partial indexes для фільтрів з високою селективністю, GIN-індекси для JSONB та full-text search. to_tsvector + GIN замість LIKE '%query%' — запобігає seq scan навіть на мільйонах записів. Аналізуємо плани через EXPLAIN ANALYZE та pg_stat_statements.

Як обрати стек для вашого проекту?

Стек Коли використовувати
Laravel + Octane CRUD, бізнес-логіка, REST/GraphQL API, адмінки
Node.js (Fastify) Realtime WebSocket, streaming, serverless, висока I/O concurrency
Go Високонавантажені мікросервіси (>10k RPS), gRPC, DevOps-інструменти
Django + DRF ML-пайплайни, інтеграція з AI, складна обробка даних
Ruby on Rails Швидкий MVP з багатим екосистемою гемів

Node.js виправданий для realtime: Laravel публікує події в Redis Pub/Sub, Node.js підписується та транслює клієнтам. Go — для goroutines (10k з'єднань на сервер — норма), але розробка повільніша, ніж Laravel.

Чому Redis критичний для продуктивності?

Redis виконує кілька ролей:

Роль Деталі
Кеш Кешування результатів важких запитів, фрагментів HTML
Черги Backend для Laravel Queue / Celery
Session store Distributed sessions в multi-instance оточенні
Pub/Sub Realtime події між сервісами
Rate limiting Sliding window counters для API throttling
Leaderboards Sorted Sets для рейтингів

Redis Cluster для горизонтального масштабування, Sentinel для автоматичного failover. Замовте консультацію щодо оптимізації Redis для вашого проекту.

Що входить в роботу під ключ

  • Архітектурне проектування (документація API, схема БД, діаграма сервісів)
  • Реалізація за узгодженим ТЗ з code review
  • Налаштування CI/CD (GitHub Actions, Docker), моніторингу (Sentry, Grafana), алертингу
  • Навантажувальне тестування (k6, wrk) зі звітом
  • Передача вихідних кодів, доступів, інструкція з деплою
  • Навчання команди замовника (2–3 сесії)
  • Гарантійна підтримка 1 місяць після здачі

Орієнтири по термінах

Задача Термін
REST API для мобільного/SPA (середня складність) 6–12 тижнів
Backend зі складною бізнес-логікою + інтеграції 12–20 тижнів
Високонавантажений сервіс на Go 8–16 тижнів
Міграція legacy PHP на Laravel 16–32 тижні

Вартість розраховується індивідуально після аналізу вимог до навантаження, інтеграцій та бізнес-логіки. Зв'яжіться з нами для безкоштовного аудиту вашого поточного backend — отримайте план оптимізації за 2 дні. Замовте консультацію та дізнайтеся, як знизити витрати на інфраструктуру на 30% без втрати продуктивності.