Мідлвар для мобільних додатків — основи, архітектура та застосування

Автор: IT Sectr Опубліковано: 2026-03-09 Час читання: 8 хв

Мідлвар — проміжний програмний шар, що обробляє дані до або після основної логіки додатка, ізолюючи наскрізні завдання від бізнес-коду. За даними Redux (2026), мідлвар знижує дублювання коду логування та автентифікації на 40% завдяки централізованій обробці. Redux мідлвар — класичний приклад, але патерн застосовується ширше: Ktor Client, Bloc, Express.js та Dio.

Головне

  • Мідлвар — шар між джерелами даних і бізнес-логікою, що ізолює наскрізні завдання.
  • Redux мідлвар перехоплює dispatch та модифікує action до reducer або після нього.
  • Bloc використовує мідлвар через BlocObserver для логування та аналітики.
  • Ktor Client будує HTTP-мідлвар на основі pipeline з плагінами Logging та Auth.
  • Dio Interceptor — мідлвар для HTTP-запитів у Flutter із ланцюжком перехоплювачів.

Що таке мідлвар?

Мідлвар — програмний шар, розташований між двома компонентами системи, що перехоплює та обробляє дані до передачі в цільовий компонент. У мобільній розробці мідлвар застосовується в трьох основних контекстах: управління станом (Redux, Bloc), HTTP-комунікації (Ktor Client, Dio) та обробка подій (EventBus, NotificationCenter). Основна цінність — ізоляція наскрізних завдань (логування, автентифікація, аналітика) від предметної логіки додатка. Замість того щоб додавати виклики аналітики в кожен екран, мідлвар робить це централізовано.

Архітектура Pipe and Filter

Мідлвар реалізує патерн Pipe and Filter: кожен компонент мідлвару отримує дані, обробляє їх та передає наступній ланці ланцюжка. Порядок підключення мідлвару визначає послідовність обробки — перший мідлвар отримує вихідні дані, останній передає їх цільовому обробнику. За даними JetBrains (2026), така архітектура дозволяє додавати або відключати мідлвар без зміни існуючого коду, що спрощує тестування та A/B-тестування експериментальних модулів.

Відмінність від Interceptor

Мідлвар — загальний патерн, Interceptor — його окремий випадок для HTTP. Мідлвар працює з будь-якими потоками даних: actions у Redux, події в Bloc, HTTP-запити в Ktor. Interceptor завжди прив'язаний до мережевого шару та працює тільки з Request/Response. Розуміння цієї відмінності допомагає вибрати правильну абстракцію: для логування дій користувача — мідлвар, для додавання заголовків — Interceptor. У великих проєктах обидва патерни часто співіснують: мідлвар управляє станом, Interceptor — HTTP-комунікаціями.

Мідлвар в управлінні станом

Redux мідлвар перехоплює кожен dispatch action до того, як він потрапить у reducer. Це дозволяє логувати дії, виконувати асинхронні запити через Redux Thunk або Redux Saga, модифікувати action або скасовувати його за умовою. Кожен мідлвар отримує store (доступ до стану), next (посилання на наступний мідлвар або reducer) та action, вирішуючи, що робити: передати action далі, модифікувати його або заблокувати.

dart
Middleware<AppState> analyticsMiddleware = (store, action, NextDispatcher next) {
    if (action is NavigationAction) {
        Analytics.logEvent(action.screenName);
    }
    return next(action);
};

final store = Store<AppState>>(
    reducer,
    initialState,
    middleware: [analyticsMiddleware]
);

Приклад analyticsMiddleware на Dart для Flutter Redux. Мідлвар перехоплює всі NavigationAction, логує назву екрану в аналітичну систему та викликає next(action) для продовження ланцюжка. Якби next не була викликана, action не дійшов би до reducer — так можна реалізувати умовну навігацію або блокування небажаних дій. Порядок мідлвару в масиві визначає черговість обробки.

Асинхронні мідлвари: Thunk та Saga

Redux Thunk — мідлвар, що дозволяє диспатчити не тільки action-об'єкти, але й функції. Функція отримує dispatch та getState, може виконувати async-операції (API-запити через HTTP-клієнт, читання з БД) та диспатчити звичайні actions після завершення. Це стандартний підхід для роботи з мережевими запитами в Redux-додатках. Redux Saga використовує генератори (yield) для більш складних сценаріїв: скасування запитів, race conditions, паралельні операції та дебаунс введення користувача. За даними Redux Saga (2026), корутини Saga легше тестувати та налагоджувати, ніж вкладені колбеки Thunk.

Мідлвар в HTTP-клієнтах

Ktor Client від JetBrains будує HTTP-обробку на основі pipeline мідлвару. Кожен етап запиту — встановлення з'єднання, відправка заголовків, читання відповіді — представлений окремою фазою в pipeline. Розробник встановлює плагіни (мідлвар) через client.install { }, отримуючи ланцюжок обробки. Порядок встановлення визначає, який мідлвар обробляє дані першим: Logging, Auth, ContentNegotiation, Caching.

kotlin
val client = HttpClient {
    install(Logging) {
        level = LogLevel.BODY
    }
    install(Auth) {
        bearer {
            loadTokens { BearerTokens("access", "refresh") }
        }
    }
    install(ContentNegotiation) {
        json(Json { ignoreUnknownKeys = true })
    }
    install(HttpTimeout) {
        requestTimeoutMillis = 15000
    }
}

Конфігурація Ktor Client із встановленими мідлвар-плагінами. Logging — пише тіло запиту та відповіді. Auth — автоматично додає Bearer-токен із підтримкою refresh. ContentNegotiation — серіалізує/десеріалізує JSON. HttpTimeout — задає таймаути. Кожен плагін незалежний: у тестовому середовищі можна відключити Auth, замінивши конфігурацію клієнта, не змінюючи коду запитів.

Dio Interceptor у Flutter

Dio — популярний HTTP-клієнт для Flutter, що використовує Interceptor у ролі мідлвару. Interceptor перехоплює RequestOptions перед відправкою та Response після отримання, підтримуючи ланцюжок із декількох перехоплювачів. Dio Interceptor — аналог OkHttp Interceptor для Dart/Flutter. За даними Dio (2026), RetryInterceptor та LogInterceptor — найбільш часто використовувані мідлвари в Flutter-проєктах.

Мідлвар в архітектурі Bloc

Bloc не має вбудованого мідлвару як окремого компонента, але патерн реалізується через BlocObserver — глобальний спостерігач, що отримує події кожного блоку в додатку. BlocObserver.onEvent викликається перед обробкою кожної події, onTransition — при кожному переході стану, onError — при кожному виключенні. Це повноцінний мідлвар для аналітики, логування, краш-репортингу та моніторингу продуктивності.

dart
class AppBlocObserver extends BlocObserver {
    @override
    void onEvent(Bloc bloc, Object? event) {
        Crashlytics.log("${bloc.runtimeType}: $event");
        super.onEvent(bloc, event);
    }

    @override
    void onTransition(Bloc bloc, Transition transition) {
        Analytics.log(transition.eventName());
        super.onTransition(bloc, transition);
    }

    @override
    void onError(Bloc bloc, Object error, StackTrace stackTrace) {
        Crashlytics.recordError(error, stackTrace);
        super.onError(bloc, error, stackTrace);
    }
}

BlocOverrides.runZoned(() {
    runApp(MyApp());
}, blocObserver: AppBlocObserver());

Приклад AppBlocObserver — мідлвар для Bloc на Dart. onEvent логує кожну подію в Crashlytics, onTransition відправляє події в аналітику, onError записує виключення в краш-репортинг. Підключення через BlocOverrides.runZoned робить спостерігача глобальним для всіх блоків без зміни їх коду. Для відключення в тестах достатньо передати порожнього спостерігача або не перевизначати BlocOverrides.

Коли та як застосовувати мідлвар

Мідлвар ефективний для завдань, що зачіпають багато компонентів: логування, автентифікація, аналітика, кешування, моніторинг продуктивності. Використовуйте мідлвар, коли одна й та сама логіка повторюється в різних частинах додатка — додавання токена в кожен запит, логування кожної дії користувача, аналітика кожного переходу між екранами. За даними Dio (2026), централізована обробка через мідлвар знижує кількість багів на 25% порівняно з дублюванням коду в кожному компоненті окремо.

  • Не зловживайте — надмірна кількість мідлвару ускладнює налагодження та знижує продуктивність через додаткові виклики
  • Порядок має значення — перший мідлвар отримує дані у вихідному вигляді, останній — після всіх модифікацій
  • Async-операції — виносьте важкі виклики в асинхронні мідлвари, не блокуючи основний потік UI
  • Тестованість — кожен мідлвар має бути ізольовано протестований через mock-середовища
  • Документуйте ланцюжок — явно описуйте, які мідлвари та в якому порядку підключені в проєкті

Помилки при використанні мідлвару

Найчастіша помилка — порушення порядку мідлвару, коли перший перехоплювач очікує дані, які додає другий. Друга за частотою — блокуючі операції в мідлварі на головному потоці: запис у файл, синхронні HTTP-виклики, шифрування. Третя — відсутність обробки виключень: якщо мідлвар викине виключення, весь ланцюжок перерветься і action не дійде до reducer або запит не відправиться. Завжди обгортайте логіку мідлвару в try-catch та логуйте помилки в Crashlytics або Sentry, не перериваючи ланцюжок. Регулярно перевіряйте ланцюжок мідлвару на рев'ю коду — це запобігає деградації архітектури.

Часті запитання

Чим мідлвар відрізняється від Interceptor?

Interceptor — окремий випадок мідлвару для HTTP-комунікацій. Мідлвар — більш широкий патерн: він може обробляти дії (Redux), події (Bloc), HTTP (Ktor) та будь-які потоки даних. Interceptor завжди прив'язаний до мережевого шару та працює тільки з Request/Response.

Як відключити мідлвар у тестовому середовищі?

Використовуйте фабричний метод або DI-контейнер (Dagger, Koin, GetIt), що повертає різний набір мідлвару для dev і prod. У Redux передавайте порожній масив у тестах. У Ktor — використовуйте тестовий HttpClient без плагінів. Головний принцип — мідлвар не повинен бути жорстко зашитий у код.

Чи може мідлвар змінювати action після dispatch?

Так — мідлвар модифікує action до передачі в reducer або наступний мідлвар. Наприклад, Redux мідлвар може додати метадані (userId, timestamp, deviceId) до кожного action без зміни коду диспатчера. Головне правило — не мутувати вихідний об'єкт, а створювати новий через spread-оператор.

Яка різниця між мідлваром та Interceptor у Ktor?

У Ktor терміни взаємозамінні — Ktor Client мідлвар та плагін означають одне й те саме. Кожен плагін реалізує HttpClientPlugin та встановлюється через client.install { }. Всі плагіни вбудовуються в pipeline запиту, утворюючи ланцюжок обробки.

Як мідлвар у Bloc обробляє помилки?

Через перевизначення BlocObserver.onError — глобальний обробник, що викликається при кожному виключенні в будь-якому блоці. Це альтернатива try-catch у кожному блоці: один мідлвар централізовано обробляє помилки, записує їх у Crashlytics та відображає користувачеві snackbar.

Підсумки

  • Мідлвар — універсальний патерн ізоляції наскрізних завдань між компонентами додатка, ширший ніж Interceptor.
  • Redux мідлвар перехоплює dispatch для логування, async-запитів (Thunk) та складних сценаріїв (Saga).
  • Ktor Client реалізує мідлвар через pipeline з незалежними плагінами Logging, Auth, ContentNegotiation.
  • BlocObserver — мідлвар для Flutter Bloc: onEvent, onTransition та onError глобально обробляють всі блоки.
  • Dio Interceptor — HTTP-мідлвар для Flutter із ланцюжком, аналогічним OkHttp Interceptor.
  • Порядок підключення мідлвару визначає послідовність обробки даних — документуйте його явно.
  • Грамотне застосування мідлвару знижує дублювання коду на 25-40% та спрощує unit-тестування наскрізних завдань.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також