API

Парадигми API та концепція REST

Еволюція від RPC до REST. Шість обмежень Філдінга. Чому термін «REST API» неточний. Порівняння HTTP API, gRPC та GraphQL.

Парадигми API та концепція REST

Ця стаття — одна з ключових у модулі. Перш ніж проєктувати API, потрібно зрозуміти філософію за ним: чому HTTP-запити виглядають саме так, чому REST — це скоріше набір обмежень, ніж стандарт, і чому термін «REST API» — найбільше джерело «холіварів» серед програмістів.

1. Історична довідка: Як з'явились мережеві API

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

Цю концепцію у 1981 році формалізував Брюс Нельсон з лабораторії Xerox PARC під назвою Remote Procedure Call (RPC) — і він же був співавтором першої практичної реалізації (Sun RPC, який існує і сьогодні під назвою ONC RPC).

RPC першого покоління: зручність ≠ продуктивність

Перші широко розповсюджені RPC-протоколи — Sun RPC, Java RMI, CORBA — дозволяли працювати з віддаленими викликами як з локальними. Вся «магія» була сховано всередині обв'язки (stub), яку генерував фреймворк.

Звучить ідеально? Але саме ця зручність стала ахіллесовою п'ятою:

🔗 Жорстка прив'язка

RPC першого покоління диктували вибір мови та платформи. Sun RPC не працював на Windows. Java RMI вимагав JVM. CORBA теоретично підтримувала будь-яку мову, але на практиці це було надзвичайно складно.

🐌 Складність проксіювання

Для перенаправлення RPC-запиту потрібно прочитати і розібрати все тіло запиту — це ресурсомістко. На відміну від HTTP, де метадані (URL, заголовки) можна прочитати без розбору тіла.

📈 Проблеми масштабування

Можливість адресувати об'єкти у пам'яті віддаленого сервера накладала величезні обмеження на масштабування.

🏗️ Складність протоколу

Вимога працювати з віддаленими викликами як з локальними призводила до високої складності протоколу через необхідність підтримувати можливості високорівневих мов програмування.

2. Поява HTTP та зміна парадигми

Паралельно з кризою RPC першого покоління відбувається стандартизація мережевих протоколів. Стек TCP/IP стає домінуючим. Але TCP/IP має суттєвий недолік з прикладної точки зору — він оперує IP-адресами, які люди не запам'ятовують.

Зручною абстракцією стала система доменних імен (DNS), а для передачі гіпертексту Тім Бернерс-Лі у 1991 році створив HTTP 0.9 — простий протокол для отримання документів. Він дозволяв відкрити TCP-з'єднання з сервером і передати рядок на кшталт GET адреса_документа.

Згодом HTTP стрімко розвивався: з'явились нові методи (POST, PUT, DELETE), статус-коди, заголовки, типи даних. HTML еволюціонував у XML, а потім у JSON як формати для API.

Loading diagram...
timeline
    title Еволюція парадигм клієнт-серверних API
    1981 : RPC (Брюс Нельсон)
    1991 : HTTP 0.9 (Тім Бернерс-Лі)
    1996 : HTTP/1.0 : CORBA, Java RMI
    1999 : HTTP/1.1 : XML-RPC, SOAP
    2000 : REST (дисертація Філдінга)
    2015 : GraphQL (Facebook) : HTTP/2
    2016 : gRPC (Google)
    2022 : HTTP/3 (QUIC)

HTTP виявився ідеологічно протилежним до RPC: він не передбачав ні нативної обв'язки для викликів, ні розділеного доступу до пам'яті. Натомість запропонував надзвичайно зручні концепції:

  • Кешування «з коробки» через заголовки
  • Прозорі проксі — проміжні вузли, що не впливають на протокол
  • URL — зрозуміла та стандартизована адресація ресурсів

Переворот: від процедур до ресурсів

У середині 1990-х відбувається поступова відмова від RPC першого покоління на користь нового підходу, де стосунки між даними та операціями перевертаються з ніг на голову:

АспектRPC (процедурний)Ресурсоорієнтований (HTTP)
Одиниця доступуІм'я операції (функції)Адреса ресурсу (URL)
Набір операційДовільний, визначений розробникомЛімітований, стандартизований (GET, POST...)
СтанМоже зберігатися на серверіКлієнт і сервер принципово не мають спільного стану
Проміжні вузлиУскладнюють роботуПрозорі (прокси, гейтвеї не впливають на протокол)
КешуванняКастомне рішенняСтандартне, через заголовки HTTP
RPC-стиль — виклик процедури
// ❌ RPC-підхід: URL описує ДІЮ
// POST /api/createOrder
// POST /api/getOrderById
// POST /api/cancelOrder

app.MapPost("/api/createOrder", (CreateOrderRequest req) =>
{
    // Проблема: всі операції через POST,
    // URL не відображає ресурси,
    // неможливо кешувати
    return Results.Ok(new { id = 42 });
});
REST-стиль — операція над ресурсом
// ✅ Ресурсоорієнтований підхід: URL описує РЕСУРС
// POST   /v1/orders      → створити
// GET    /v1/orders/42    → отримати
// DELETE /v1/orders/42    → скасувати

app.MapPost("/v1/orders", (CreateOrderRequest req) =>
{
    // Метод HTTP визначає операцію
    // URL ідентифікує ресурс
    // GET-запити можна кешувати автоматично
    return Results.Created("/v1/orders/42", new { id = 42 });
});

3. REST: Що насправді написав Філдінг

У 2000 році один із авторів специфікації HTTP — Рой Філдінг — захистив докторську дисертацію «Архітектурні стилі та дизайн архітектури мережевого програмного забезпечення». П'ята глава мала назву «Representational State Transfer (REST)».

Критично важливо зрозуміти: дисертація Філдінга — це абстрактний огляд розподіленої мережевої архітектури. Вона не прив'язана ні до HTTP, ні до URL. Вона не присвячена правилам дизайну API. Філдінг методично перераховує обмеження, з якими стикається розробник розподіленого мережевого ПЗ.

Шість обмежень REST

1. Клієнт-серверна архітектура

Клієнт і сервер не знають внутрішнього устрою один одного. Це забезпечує незалежну еволюцію обох сторін.

2. Stateless (без стану)

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

3. Кешування

Дані повинні розмічатися як кешовані або некешовані. Це дозволяє клієнту та проміжним проксі зберігати відповіді, зменшуючи навантаження на сервер.

4. Уніфікований інтерфейс

Інтерфейси взаємодії між компонентами повинні бути стандартизовані. Саме тому HTTP визначає фіксований набір методів (GET, POST, PUT, DELETE), а не довільні процедури.

5. Багатошарова система

Мережеві системи є багатошаровими — сервер може бути лише проксі до інших серверів. Клієнт не повинен знати, чи спілкується він безпосередньо з сервером, чи з проміжним вузлом.

6. Code-On-Demand (опціонально)

Функціональність клієнта може бути розширена через поставку коду з сервера (наприклад, JavaScript у браузері).

Loading diagram...
graph TD
    subgraph "6 обмежень REST"
        A["1. Клієнт-Сервер"] --> B["2. Stateless"]
        B --> C["3. Кешування"]
        C --> D["4. Уніфікований інтерфейс"]
        D --> E["5. Багатошарова система"]
        E --> F["6. Code-On-Demand<br/>(опціонально)"]
    end

    style A fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style B fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style C fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style D fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style E fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style F fill:#f59e0b,stroke:#b45309,color:#ffffff

4. Міфологія REST: Чому «REST API» — неточний термін

Увага: Ця частина може здивувати, але вона дуже важлива для вашого професійного розвитку. Більшість того, що ви читали про REST в інтернеті — це спрощення або помилки.

Ключовий висновок із визначення REST за Філдінгом-2000: практично будь-яке мережеве ПЗ у світі відповідає принципам REST, за дуже рідкісними винятками.

Справді:

  • Складно уявити систему без хоч якоїсь стандартизації взаємодії (хоча б TCP/IP)
  • Якщо є інтерфейс, під нього завжди можна мімікрувати → клієнт і сервер незалежні
  • Якщо можна зробити альтернативну реалізацію сервера → можна поставити проксі → багатошаровість
  • Клієнт — обчислювальна машина → завжди зберігає якийсь стан і кешує якісь дані

Ще більше плутанини: Філдінг-2008

У 2008 році Філдінг випустив роз'яснення, де додав ще суворіші вимоги:

  • Клієнт взагалі нічого не повинен знати про API наперед
  • Не повинно бути фіксованих шаблонів URL — клієнт має отримувати посилання з відповідей сервера (концепція HATEOAS — Hypermedia As The Engine Of Application State)
З книги Константинова: «Жодна існуюча система у світі не відповідає опису REST за Філдінгом-2008». Термін «REST API» не несе конкретного сенсу — це «химера», породжена редукцією абстракцій Філдінга в умах мільйонів програмістів. Ми будемо використовувати термін «HTTP API» як більш точний і практичний.

Що ми маємо на увазі під HTTP API

У цьому модулі HTTP API означає:

  1. Протоколом є HTTP версії 1.1 і вище
  2. Форматом даних є JSON
  3. Ідентифікаторами ресурсів є URL відповідно до стандарту
  4. Семантика HTTP-дієслів (методів) відповідає специфікації
  5. Жодні веб-стандарти не порушуються навмисно
Це — HTTP API
var app = WebApplication.Create(args);

// URL ідентифікує ресурс: замовлення з id=42
// GET — семантика «отримати»
// Відповідь у JSON
app.MapGet("/v1/orders/{id}", (int id) =>
    Results.Ok(new 
    { 
        id, 
        recipe = "lungo",
        status = "processing" 
    }));

// POST — семантика «створити»
// Content-Type: application/json
app.MapPost("/v1/orders", (OrderRequest req) =>
    Results.Created($"/v1/orders/42", new { id = 42 }));

app.Run();

record OrderRequest(string Recipe, string CoffeeMachineId);

5. Сучасні альтернативи: gRPC, GraphQL

Починаючи з кінця 2010-х ми спостерігаємо розквіт RPC-технологій нового покоління — або, точніше, комбінованих технологій, які одночасно:

  • Зручні — поставляються з обв'язкою для кодогенерації
  • Інтероперабельні — працюють поверх стандартизованих протоколів
  • Масштабовані — абстрагують поняття ресурсу

gRPC

gRPC — класична технологія другого покоління від Google:

✅ Переваги

  • Використовує HTTP/2 та ефективний Protobuf
  • Contract-first: розробка починається зі специфікації .proto
  • Кодогенерація для зручної роботи
  • Висока продуктивність

❌ Недоліки

  • Складність налагодження (бінарний формат)
  • Слабка підтримка браузерів
  • Менша поширеність → вищий поріг входу
  • Потенційна залежність від Google
Приклад gRPC сервісу
// coffee_service.proto
syntax = "proto3";

service CoffeeService {
  // RPC-стиль: ім'я операції
  rpc CreateOrder(CreateOrderRequest) 
    returns (OrderResponse);
  rpc GetOrder(GetOrderRequest) 
    returns (OrderResponse);
}

message CreateOrderRequest {
  string recipe = 1;
  string coffee_machine_id = 2;
}

message OrderResponse {
  int32 id = 1;
  string status = 2;
}

GraphQL

GraphQL від Facebook — підхід, що об'єднує концепцію «ресурсів» з надзвичайно багатою мовою запитів:

# Клієнт точно вказує, які поля потрібні
query {
  order(id: 42) {
    id
    recipe
    status
    machine {
      location
    }
  }
}
Основна область застосування GraphQL — насичені різнорідними даними предметні області (соціальні мережі, e-commerce з багатьма зв'язками). Надання зовнішніх GraphQL API поки що екзотика, оскільки з ростом кількості даних GraphQL-сервісом стає дуже складно управляти.

Порівняння технологій

АспектHTTP API (JSON)gRPCGraphQL
Формат данихJSON (текстовий)Protobuf (бінарний)JSON (текстовий)
ПротоколHTTP/1.1+HTTP/2HTTP/1.1+
ПідхідРесурсоорієнтованийContract-first RPCМова запитів
Фіксований набір полівТак (весь ресурс)Так (за .proto)Ні (клієнт обирає)
Кешування HTTPСтандартнеОбмеженеСкладне
СтрімінгSSE, WebSocketВбудований (bidirectional)Subscriptions
Порог входуНизькийСереднійСередній–Високий
ІнструментиНайбільша екосистемаGoogle-екосистемаFacebook-екосистема

Принциповий висновок

Фактично, ідеологічна різниця між сучасним HTTP API та сучасним RPC зводиться до двох речей:

  1. Адресація: в HTTP API одиницею доступу є ресурс (а параметри операції передаються додатково), в RPC — ім'я операції (а адреси ресурсів передаються додатково)
  2. Кешування: HTTP API стандартно розмічає кешовані дані, RPC — як правило, ні

І головне: майже всі сучасні протоколи працюють поверх HTTP. Тому gRPC одночасно є HTTP API (в технічному сенсі використання протоколу HTTP).


6. Вибір технології: Коли що використовувати

HTTP API (JSON)

Коли: Публічні API, мобільні та веб-клієнти, інтеграція з партнерами. Чому: Зрозумілий максимально широкому колу розробників, працює скрізь.

gRPC

Коли: Внутрішні мікросервіси, server-to-server комунікація, high-performance системи. Чому: Висока продуктивність, кодогенерація, типобезпека.

GraphQL

Коли: Насичені даними клієнтські додатки (dashboard-и, соцмережі), внутрішні API з багатьма зв'язками. Чому: Клієнт сам обирає потрібні дані, зменшуючи кількість запитів.
З книги Константинова: Для публічних API надання JSON-over-HTTP ендпоінтів є вибором за замовчуванням. Практика надання публічних API у форматі gRPC поступово набирає популярності, але поки що незначна на загальному фоні. Проблема вибору технології виникає лише для непублічних API загального призначення.

7. Головна перевага HTTP API: Промежуточні агенти

Чому HTTP API вижив, коли з'явились «швидші» та «зручніші» альтернативи? Відповідь — у промежуточних агентах.

Сучасний стек взаємодії між клієнтом і сервером — багатошаровий:

Loading diagram...
graph LR
    A["📱 Клієнт"] --> B["CDN / Cache"]
    B --> C["API Gateway"]
    C --> D["Load Balancer"]
    D --> E["Reverse Proxy"]
    E --> F["🖥️ Сервер"]

    style A fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style F fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style B fill:#f59e0b,stroke:#b45309,color:#ffffff
    style C fill:#f59e0b,stroke:#b45309,color:#ffffff
    style D fill:#f59e0b,stroke:#b45309,color:#ffffff
    style E fill:#f59e0b,stroke:#b45309,color:#ffffff

Кожен із цих проміжних агентів може читати метадані HTTP (URL, заголовки, статус-коди) без розбору тіла запиту, і автоматично:

  • Кешувати відповіді (CDN, проксі)
  • Логувати запити (nginx access logs → Prometheus → Grafana)
  • Балансувати навантаження
  • Шардувати дані за URL
  • Налаштовувати таймаути та retry-політики

Для RPC-протоколів, де вся інформація захована в тілі запиту, жоден із цих агентів не зможе «зрозуміти» запит без спеціальної підтримки протоколу.

Головний принцип HTTP API (з книги Константинова): краще проєктувати API так, щоб промежуточні агенти могли читати та інтерпретувати метадані запиту і відповіді.

8. Практичні завдання

Рівень 1: Базовий

Рівень 2: Аналітичний


9. Резюме

Від RPC до REST

RPC першого покоління (Sun RPC, CORBA) були зручними, але створювали жорстку залежність між клієнтом і сервером. HTTP та ресурсоорієнтований підхід вирішили це.

REST — обмеження, не стандарт

REST за Філдінгом — це 6 абстрактних обмежень, а не набір конкретних правил для URL-ів. Термін «REST API» — неформальний і не несе конкретного сенсу.

HTTP API — наш термін

JSON-over-HTTP ендпоінти, що використовують семантику HTTP (методи, статус-коди, URL) відповідно до стандартів. Це те, що більшість людей насправді мають на увазі, кажучи «REST API».

Альтернативи мають свою нішу

gRPC — для internal high-performance. GraphQL — для складних data-driven UI. HTTP API — вибір за замовчуванням для публічних сервісів.

Далі: у наступній статті ми детально розберемо складові HTTP-запитів — URL-адресацію, HTTP-методи (GET, POST, PUT, DELETE, PATCH), заголовки та статус-коди відповідей. Це фундамент, на якому будується весь дизайн HTTP API.

Copyright © 2026