API без привязки к транспорту — RPC через HTTP/WebSocket

Бизнес-логика не знает про сеть. Транспорт меняется (HTTP → WebSocket → IPC) без переписывания функций.

Что это

Идеальный API — это набор асинхронных функций, которые работают и на клиенте, и на сервере, и не зависят от того, как они вызываются. Транспорт — отдельный слой, который маршалит вызов в сетевой запрос.

Это RPC-подход: на клиенте лежит «представитель» серверной функции; вызов выглядит как обычный await api.method(args).

API / Пример

// api/createCircle.js — серверная функция
module.exports = async ({ x, y, r }) => {
  const id = nextId;
  shapes.set(id, { type: 'circle', x, y, r });
  return { id };
};

// server — endpoint выдаёт список функций
// клиент построит зеркальный объект API
const api = {};
for (const name of methodNames) {
  api[name] = async (args) => {
    const res = await fetch(`/api/${name}`, {
      method: 'POST',
      body: JSON.stringify(args)
    });
    return res.json();
  };
}

// Бизнес-код одинаков на клиенте и сервере
const circle = await api.createCircle({ x: 100, y: 100, r: 50 });

Принципы

  1. Все экспортируемые функции async — единый контракт, прозрачность.
  2. Функции не знают про сеть — никакого req/res внутри логики.
  3. Каждая функция = один файл — легко найти, легко тестировать.
  4. Endpoint со списком функций — клиент сам строит зеркальный объект.
  5. throw → reject — ошибки летят к вызывающему как rejected promise.
  6. Транспорт — отдельный слой — HTTP/WebSocket/IPC меняются без правок логики.

Производительность / Подводные камни

  • Сериализация JSON — большие объекты приходят частями (chunks); собирать на сервере и на клиенте.
  • Прозрачность через проксиnew Proxy({}, { get: (_, name) => (args) => call(name, args) }) даёт API без явного списка методов.
  • Версионирование — добавил параметр → старый клиент не знает; нужны валидаторы и default-значения.
  • HTTP overhead на RPC — для частых вызовов лучше WebSocket с мультиплексированием стримов (как Metacom).
  • fetch/http.request совместимы — клиентский полифил fetch на XHR в браузере и нода-fetch поверх http.get дают одинаковый контракт.

🎓 Источники

  • 🎓 Разработка API на Node.js (клиент и сервер) · 2019-03-28

    • Тезисы: API без зависимостей и без привязки к транспорту; все функции async; throw в async = reject; endpoint отдаёт список функций; клиент строит зеркальный объект; функция-«представитель» серверной функции на клиенте; код гуляет между клиентом и сервером.
    • Цитата: «Заметьте, что во всех этих функциях я ничего не знаю про сеть вообще. Все эти функции могут исполняться и на клиенте, и на сервере, независимо от протокола.»
  • 🎓 HTTP requests in browser and Node.js: XMLHttpRequest, fetch · 2019-03-21

    • Тезисы: полифил fetch поверх http.get/https.get на сервере; клиентский fetch через XHR с тем же контрактом; обёртка XHR в Promise; abstraction layer над HTTP — бизнес-код не знает про HTTP-вызовы.
  • 🎓 Metacom — сеть прозрачна для API при выборе транспорта HTTP, HTTPS, HTTP2, WebSocket · 2025-12-11

    • Тезисы: один API-контракт, разные транспорты подбираются автоматически; HTTP/2, WebSocket, HTTPS — выбор по доступности; мультиплексация стримов в одном TCP.

См. также