Як я створив open-source HTTP client для service-to-service комунікації
У якийсь момент я зловив себе на думці, що майже в кожному проєкті пишу одне й те саме.
Серйозно — знову і знову:
- HTTP-клієнт
- retry
- auth
- логування
- обробка помилок
І кожен раз це трохи інша реалізація і наче все знайоме, але по факту — це новий велосипед.
Проблема, яка повторюється в кожному проєкті
Я працюю з Node.js + TypeScript, часто це мікросервіси або якісь інтеграції.
І майже в кожному проєкті є одна й та сама задача — нормально комунікувати між сервісами.
На словах це звучить дуже просто: «ну зробити HTTP-запит і все».
Але потім починається реальність:
- що робити, якщо сервіс тимчасово не відповідає?
- як правильно зробити retry (а не просто «повторити ще раз»)?
- куди засунути auth, щоб він не був розмазаний по всьому коду?
- як виглядають нормальні помилки?
- що робити з логуванням / трейсінгом?
В результаті зазвичай один із сценаріїв:
- у кожного сервісу свій «унікальний клієнт»
- або копіпаст з якогось минулого проєкту
- або якась бібліотека + обгортка
Чому готові рішення не дуже заходили
Я пробував різне:
- чистий
fetch axios- свої обгортки
Воно все працює, без питань. Але постійно виникало відчуття, що чогось не вистачає.
👉 вони не дають передбачуваної поведінки «з коробки»
Наприклад:
- retry треба вигадувати самому
- помилки — хто як зробив, так і є
- hooks або відсутні, або незручні
- auth часто розмазаний по коду
І в якийсь момент я зрозумів, що вже кілька разів написав майже один і той самий HTTP-клієнт 😅
Тому вирішив винести це в окремий пакет
Так зʼявився dfsync (Data Flow Sync).
Перший пакет — @dfsync/client.
Ідея дуже проста: зробити HTTP client з передбачуваною поведінкою для service-to-service комунікації. Не «універсальний комбайн», а нормальний робочий інструмент.

Що він робить (коротко)
- typed responses
- консистентні помилки
- auth (Bearer, API key, custom)
- lifecycle hooks (beforeRequest, afterResponse, onError)
- retry з конфігурацією
- таймаути
Але ключове — не список фіч, а те, як вони працюють разом.
Як це виглядає в коді
import { createClient } from '@dfsync/client';
const client = createClient({
baseUrl: 'https://api.example.com',
timeout: 5000,
retry: {
attempts: 3,
backoff: 'exponential',
baseDelayMs: 300,
},
});
const users = await client.get('/users');Без додаткових обгорток та магії 🧙.
Про retry (бо це біль)
Retry — це взагалі окрема історія.
Часто це або:
- самописний код
- якась стороння бібліотека
- або «та ладно, і так зійде»
Тут воно просто конфігурується:
retry: {
attempts: 3,
backoff: 'exponential',
baseDelayMs: 300,
}І ти вже знаєш, як воно поводиться.
Hooks — щоб не ламати клієнт під себе
Ще одна штука, яка мені була важлива — можливість розширювати поведінку без «хаків».
hooks: {
beforeRequest: async (ctx) => {
ctx.headers.set('x-request-id', crypto.randomUUID());
},
}І далі вже можна додавати:
- логування
- трейсінг
- кастомний auth
...не переписуючи сам клієнт.
Що я намагався зробити
Якщо коротко, то не «ще одну бібліотеку», а щось з нормальними принципами:
- передбачувана поведінка
- мінімум зайвого
- розширюваність через hooks
- TypeScript як база, а не «додаток зверху»
Поточний стан
Проєкт ще на старті, але базові речі вже є:
- HTTP client
- retry
- auth
- hooks
- error handling
Далі хочу додати:
- логування / метрики
- retry metadata
- валідацію відповідей
- а потім ще щось цікаве...
Якщо цікаво подивитись
⭐ GitHub:
📦 NPM:
www.npmjs.com/package/@dfsync/client
LinkedIn сторінка (якщо цікаво слідкувати за розвитком):
https://www.linkedin.com/company/dfsync
Буду радий фідбеку
Особливо якщо ви працюєте з:
- мікросервісами
- internal APIs
- інтеграціями
Цікаво почути:
👉 як ви це зараз вирішуєте
👉 де болить
👉 чого не вистачає в існуючих рішеннях
Висновок
Я не намагаюсь зробити «бібліотеку на всі випадки життя».
Швидше — нормальний, передбачуваний інструмент, який не хочеться переписувати в кожному новому проєкті 🙂
Якщо вам це заходить то буду радий фідбеку та ⭐ на GitHub
2 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарівПроблема знайома. Теж дратує кожен раз городити retry, auth і логування з нуля. Підхід з hooks сподобався — гнучко і без копіпасту. Подивлюся бібліотеку, дякую!
Дякую за відгук! 🙌
Саме через ці речі і зʼявилась ідея dfsync.
Зараз рухаюсь за roadmap, поступово додаю нові можливості.