Каскадна маршрутизація
Каскадна маршрутизація дозволяє визначити кілька upstream цілей для одного запиту. MirApi спробує їх послідовно (Priority) або паралельно (Race) і поверне першу успішну відповідь.
Каскадні маршрути налаштовуються у вашому дашборді та активуються заголовком X-Route-Key.
Налаштування маршруту у дашборді
Section titled “Налаштування маршруту у дашборді”- Відкрийте Routes → Створити маршрут
- Вкажіть ім’я (наприклад,
ai-providers) - Додайте цілі — список повних URL через кому:
https://api.openai.com/v1/chat/completions,https://api.anthropic.com/v1/messages,https://api.groq.com/openai/v1/chat/completions
- Оберіть стратегію: Priority або Race
- Задайте тайм-аут на ціль (мілісекунди)
- Опційно налаштуйте body mapping та витягнення відповіді

Активація маршруту
Section titled “Активація маршруту”curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: ai-providers" \ -H "X-Identity-Key: Bearer $OPENAI_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Привіт"}]}'Стратегії каскаду
Section titled “Стратегії каскаду”Priority (Послідовний failover)
Section titled “Priority (Послідовний failover)”Цілі пробуються по порядку. Наступна ціль пробується лише якщо попередня провалилась (5xx, тайм-аут або помилка з’єднання).
Ціль 1: https://api.openai.com/... → збій (503)Ціль 2: https://api.anthropic.com/... → збій (тайм-аут)Ціль 3: https://api.groq.com/... → успіх ✓
Відповідь: X-Rescued: cascade_fallbackНайкраще для:
- Економії коштів (лише один API-виклик у happy path)
- Платіжних API де потрібний детермінований порядок
- Будь-яких сценаріїв де важливий пріоритет
# AI провайдер — спочатку OpenAI, потім Anthropic, потім Groqcurl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: ai-priority" \ -H "X-Identity-Key: Bearer $OPENAI_KEY" \ -H "Content-Type: application/json" \ -d '{"messages": [{"role": "user", "content": "Що таке Go?"}]}'Race (Паралельно)
Section titled “Race (Паралельно)”Всі цілі викликаються одночасно. Перша успішна відповідь перемагає; решта скасовуються через context cancellation.
Ціль 1: https://api.openai.com/... → відповів за 1200ms ✗ (програв)Ціль 2: https://api.anthropic.com/... → відповів за 890ms ✗ (програв)Ціль 3: https://api.groq.com/... → відповів за 89ms ✓ (переміг)Найкраще для:
- Ультранизьких затримок де час відповіді критичний
- Read-only запитів (курси валют, пошук, ембеддинги)
- Коли всі провайдери повертають еквівалентні відповіді
curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: ai-race" \ -H "Content-Type: application/json" \ -d '{"messages": [{"role": "user", "content": "Швидке питання"}]}'Комбінування з іншими функціями
Section titled “Комбінування з іншими функціями”Маршрут + Повтори
Section titled “Маршрут + Повтори”curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: payment-cascade" \ -H "X-Retry-Count: 2" \ -H "X-Retry-Delay: 300ms" \ -H "X-Proxy-Timeout: 10s" \ -H "X-Attempt-Timeout: 2s" \ -d '{"amount": 9900, "currency": "usd"}'# Ціль 1 повторюється до 2 разів перед переходом до Цілі 2Маршрут + Async Webhook
Section titled “Маршрут + Async Webhook”curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: payment-cascade" \ -H "X-Webhook-Callback: https://your-app.com/payments/done" \ -H "X-Proxy-Idempotency-Key: order_789_pay_1" \ -d '{"amount": 9900, "currency": "usd"}'# Повертає 202 негайно# Воркер виконує повний каскад у фоні# POST з першою успішною відповіддю на callbackМаршрут + Smart Cache
Section titled “Маршрут + Smart Cache”curl https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Route-Key: exchange-rates-cascade" \ -H "X-Smart-Cache: 300s"# Пробує всі цілі маршруту# Всі провалились → кеш → X-Rescued: cacheПерсоналізована авторизація для каскадних маршрутів (Route Target Auth)
Section titled “Персоналізована авторизація для каскадних маршрутів (Route Target Auth)”У каскадній маршрутизації (Cascade Routing) додано можливість налаштовувати унікальну авторизацію для кожного окремого сервісу (Upstream URL) у межах одного маршруту.
💡 Чому це важливо?
Section titled “💡 Чому це важливо?”Раніш при перенаправленні запиту по каскаду (наприклад, Stripe ➔ Adyen ➔ Custom Bank) проксі намагався використовувати один спільний заголовок авторизації для всіх сервісів. Це обмежувало використання каскадів, оскільки різні платіжні шлюзи та API вимагають різних форматів автентифікації.
Тепер ви можете безпечно зв’язати кожен сервіс у каскаді з його власними обліковими даними з бази даних, вказавши для кожного індивідуальне ім’я HTTP-заголовка та шаблон підстановки ключа.
🛠️ Як це налаштувати (Приклад)
Section titled “🛠️ Як це налаштувати (Приклад)”Уявімо каскадний маршрут payment-cascade. Якщо основний шлюз (Stripe) поверне помилку, запит буде автоматично перенаправлено на резервний шлюз (Custom Bank API). У кожного з них своя авторизація.
Приклад JSON-payload запиту для створення такого маршруту:
{ "route_key": "payment-cascade", "strategy": "priority", "targets": [ { "priority": 1, "target_url": "https://api.stripe.com/v1/charges", "timeout_ms": 10000, "credential_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "auth_header": "Authorization", "auth_template": "Bearer {{secret}}" }, { "priority": 2, "target_url": "https://api.custombank.com/v1/payments", "timeout_ms": 15000, "credential_id": "c3098522-8356-4c91-9e2c-29ad9c42c943", "auth_header": "X-Bank-Token", "auth_template": "{{secret}}" } ]}🔍 Деталі конфігурації параметрів:
Section titled “🔍 Деталі конфігурації параметрів:”credential_id(опціонально) — ID зашифрованого ключа авторизації у вашому сейфі Credentials. Якщо поле не вказано або залишене порожнім (null/""), запит до цього таргету буде надіслано без авторизації (або з оригінальними заголовками клієнта).auth_header(за замовчуванням:Authorization) — назва HTTP-заголовка, у який проксі вставить ключ під час проксіювання.auth_template(за замовчуванням:Bearer {{secret}}) — шаблон форматування. Проксі автоматично розшифрує токен вашимX-Proxy-Master-Keyі замінить плейсхолдер{{secret}}на реальний розшифрований ключ.
🔒 Безпека на рівні Edge
Section titled “🔒 Безпека на рівні Edge”Усі облікові дані (credential_id) зберігаються в базі даних у зашифрованому вигляді (алгоритм AES-GCM). Розшифрування відбувається безпосередньо в оперативній пам’яті проксі в момент виконання запиту за допомогою ключа X-Proxy-Master-Key, який клієнт передає в заголовках запиту. Ключі розшифрування ніколи не зберігаються на наших дисках.
Маппінг тіла запиту цілі
Section titled “Маппінг тіла запиту цілі”Маппінг тіла запиту розбирає JSON-тіло вхідного запиту, перейменовує ключі, обходить вкладені поля та масиви, і формує запит перед відправкою на upstream. Перейменовані ключі-джерела автоматично видаляються.
Формат правила маппінгу — розділений комами список правил: шлях_джерела=>шлях_цілі або шлях_джерела=>шлях_цілі(шаблон).
Підтримуваний синтаксис шляху
Section titled “Підтримуваний синтаксис шляху”| Можливість | Приклад | Опис |
|---|---|---|
| Плоске перейменування | amount=>sum | Перейменовує кореневий ключ |
| Вкладений об’єкт (dot-notation) | data.order=>data.order_id | Перейменовує order на order_id всередині об’єкта data |
Перебір масиву з [] | data.orders[].order=>data.orders[].order_id | Перейменовує order на order_id у кожному елементі масиву orders |
Перебір масиву без [] | data.orders.order=>data.orders.order_id | Те саме — дужки необов’язкові, визначаються автоматично |
Шаблон значення {value} | order=>order_text(Order ID: #{value}) | Форматує значення поля у рядковий шаблон |
Міжпольовий шаблон {field_name} | status=>status(Order {order} status is {value}) | Інтерполює значення інших полів з поточного JSON-контексту |
Як це працює:
Section titled “Як це працює:”- Ваш клієнт надсилає запит до проксі-шлюзу з оригінальною структурою JSON.
- Шлюз перехоплює тіло запиту і перед відправкою на upstream перейменовує та трансформує ключі згідно з
body_mapцієї цілі. - Вкладені шляхи та елементи масивів обходяться автоматично. Решта ключів залишаються без змін.
A. Плоске перейменування:
// body_map: "amount=>sum, currency=>cur"// Вхід: {"amount": 100, "currency": "USD"}// Вихід: {"sum": 100, "cur": "USD"}B. Вкладені об’єкти:
// body_map: "data.order=>data.order_id"// Вхід: {"action": "get_status", "data": {"order": 353454876}}// Вихід: {"action": "get_status", "data": {"order_id": 353454876}}C. Перебір масиву:
// body_map: "data.orders[].order=>data.orders[].order_id"// або "data.orders.order=>data.orders.order_id"// Вхід: {"data": {"orders": [{"order": 101}, {"order": 102}]}}// Вихід: {"data": {"orders": [{"order_id": 101}, {"order_id": 102}]}}D. Динамічний шаблон значення {value}:
Форматує значення поля у рядковий шаблон. {value} — пластина для значення джерельного поля:
// body_map: "order=>order_text(Order ID: #{value})"// Вхід: {"order": 101}// Вихід: {"order_text": "Order ID: #101"}E. Міжпольовий шаблон {field_name}:
Інтерполює значення інших полів з того ж JSON-контексту. Поле шукається спочатку в поточному об’єкті, а потім у глобальному корені:
// body_map: "status=>status(Order {order} status is {value})"// Вхід: {"order": 101, "status": "success"}// Вихід: {"order": 101, "status": "Order 101 status is success"}F. Посилання на сусідні поля у масивах:
Доступає до сусідніх ключів всередині кожного окремого елементу масиву під час ітерації:
// body_map: "data.orders.status=>data.orders.status_text(Order {order} is {value})"// Вхід: {"data": {"orders": [{"order": 101, "status": "success"}, {"order": 102, "status": "fail"}]}}// Вихід: {"data": {"orders": [{"order": 101, "status_text": "Order 101 is success"}, {"order": 102, "status_text": "Order 102 is fail"}]}}
---
## Власні умови відкату по тілу відповіді
За замовчуванням каскадна маршрутизація переходить до наступної цілі лише тоді, коли поточний ендпоінт повертає статус `5xx`, виникає тайм-аут або помилка з'єднання.
Однак багато API (особливо платіжні шлюзи) повертають статус `200 OK` навіть тоді, коли транзакцію відхилено або вона завершилася помилкою. Для підтримки маршрутизації на основі бізнес-логіки збоїв, кожна ціль маршруту може визначати власну умову відкату у дашборді чи базі даних за допомогою двох параметрів:- `fallback_field`: вираз JSONPath, що вказує на поле в JSON відповіді для перевірки. Префікс `$.` є **необов'язковим** — додається автоматично, якщо відсутній. Підтримуються вкладені об'єкти (dot-notation) та елементи масиву (нотація `[]`).- `fallback_value`: рядкове значення для співпадіння (регістронезалежна перевірка на входження підрядка).
### Підтримуваний синтаксис `fallback_field`
| Приклад | Еквівалентно | Опис ||---|---|---|| `status` | `$.status` | Поле на верхньому рівні || `error.code` | `$.error.code` | Поле вкладеного об'єкта || `errors[].code` | `$.errors[*].code` | Поле всередині будь-якого елемента масиву |
### Як це працює:1. Цільовий ендпоінт повертає успішний код статусу (менше `500`).2. Шлюз зчитує тіло відповіді та витягує значення поля за вказаним шляхом JSONPath у `fallback_field`.3. Якщо витягнуте значення містить `fallback_value` як підрядок, шлюз розглядає цю відповідь як **помилку**.4. Шлюз відкидає цю відповідь, логує спрацювання умови та негайно переходить до наступної цілі у ланцюжку каскаду.

### Приклад: Відкат при відхиленні платежуUpstream платіжного процесора повернув статус `200 OK`, але платіж відхилено:```json{ "transaction_id": "tx_abc123", "status": "declined", "failure_reason": "insufficient_funds"}Налаштувавши ціль параметрами:
- Fallback Field:
status(або$.status) - Fallback Value:
declined
Шлюз перехопить 200 OK, виявить, що $.status дорівнює "declined", трактуватиме це як збій і надішле запит на оплату до наступного резервного банку у вашому каскаді.
Приклад: Відкат за кодом помилки в масиві
Section titled “Приклад: Відкат за кодом помилки в масиві”Upstream повертає помилки як масив:
{ "errors": [{"code": "card_declined", "message": "Недостатньо коштів"}]}Налаштувавши ціль параметрами:
- Fallback Field:
errors[].code - Fallback Value:
card_declined
Шлюз перевіряє поле code кожного елемента масиву errors і тригерить відкат, якщо будь-яке з них співпадає.
Захист від петель
Section titled “Захист від петель”Шлюз валідує всі цільові URL щодо власних IP-адрес та хостнеймів. Будь-яка цільова URL що резолвиться до самого проксі блокується з 400 Bad Request.
Заголовок відповіді
Section titled “Заголовок відповіді”Коли використовується не первинна ціль:
HTTP/1.1 200 OKX-Rescued: cascade_fallbackЯкщо первинна ціль (перша у списку) успішна — X-Rescued не додається.