Що таке API. Клієнт-серверна архітектура
Що таке API. Клієнт-серверна архітектура
1. Проблема: Чому програми не можуть просто «поговорити»?
Уявіть ситуацію: ви розробляєте мобільний застосунок для замовлення кави. Користувач натискає кнопку «Замовити лунго», і... що відбувається далі?
Десь на сервері є база даних із рецептами, кавовими машинами, цінами, поточними замовленнями. Ваш мобільний застосунок не має прямого доступу до цієї бази — і це правильно. Якби кожен телефон мав прямий доступ до серверної бази даних, це було б:
- Небезпечно — будь-хто міг би змінити ціни або видалити замовлення інших людей.
- Крихко — зміна структури бази зламала б усі клієнтські додатки одночасно.
- Неможливо масштабувати — мільйони прямих підключень до однієї бази покладуть сервер за лічені секунди.
Потрібен посередник — чітко визначений контракт, який каже: «Ось що ти можеш запитати, ось у якому форматі, і ось що ти отримаєш у відповідь». Цей контракт називається API.
Що ви дізнаєтесь?
- Що таке API і чому це не просто «набір URL-адрес»
- Клієнт-серверна модель та її фундаментальні принципи
- Типи API за аудиторією: внутрішнє, партнерське, публічне
- Чому HTTP API є вибором за замовчуванням для публічних сервісів
Пререквізити
- Базове розуміння протоколу HTTP (запити, відповіді, статус-коди)
- Основи мови C# та ASP.NET Core Minimal API
2. Визначення: Що таке API?
API (Application Programming Interface, програмний інтерфейс застосунку) — це контракт між двома програмними компонентами, який визначає:
- Які операції доступні (наприклад, «створити замовлення», «отримати список рецептів»).
- Який формат мають запити та відповіді (параметри, типи даних, структура).
- Які гарантії надає сервер (що станеться при помилці, як довго кешувати відповідь).
Важливо розуміти: API — це не реалізація, а специфікація. Меню ресторану не змінюється від того, чи працює на кухні шеф-кухар або стажер. Так само, API визначає контракт взаємодії, а не те, як саме сервер виконує запит всередині.
Чому API — це не просто «набір URL-адрес»?
Поширена помилка — ототожнювати API з переліком ендпоінтів (URL-адрес). Але API — поняття значно ширше:
| Аспект | Просто URL-адреси | Повноцінний API |
|---|---|---|
| Формат даних | Не визначений | JSON, XML, Protobuf — чітко задані |
| Обробка помилок | Довільна | Стандартизовані коди та формати |
| Версіонування | Відсутнє | Продумана стратегія сумісності |
| Документація | Немає | OpenAPI/Swagger специфікація |
| Гарантії | Жодних | SLA, ліміти, політика кешування |
| Безпека | Не продумана | Аутентифікація, авторизація, rate limiting |
Саме тому дизайн API — це окрема інженерна дисципліна, якій присвячено цей модуль.
3. Клієнт-серверна архітектура
Базова модель
Клієнт-серверна архітектура — це фундаментальний паттерн побудови розподілених систем, де компоненти поділяються на дві ролі:
- Клієнт — ініціатор запиту. Це може бути мобільний застосунок, браузер, інший сервер або навіть IoT-пристрій.
- Сервер — обробник запиту. Він зберігає дані, виконує бізнес-логіку та повертає відповідь.
Ключовий принцип цієї моделі: клієнт і сервер не знають внутрішнього устрою один одного. Клієнт не знає, чи сервер написаний на C#, Python чи Go. Сервер не знає, чи клієнт — це браузер, мобільний додаток чи скрипт у терміналі. Вони спілкуються виключно через контракт API.
Чому це важливо?
Ця незалежність має величезні практичні наслідки:
🔄 Незалежна еволюція
📱 Мультиплатформність
⚡ Масштабування
🧪 Тестування
4. Типи API за аудиторією
Не всі API однакові. Залежно від того, хто є споживачем API, змінюються вимоги до його дизайну, документації та безпеки.
Внутрішнє API (Internal / Private API)
Використовується тільки всередині організації — для взаємодії між мікросервісами, внутрішніми інструментами, бекенд-компонентами.
// Внутрішній API для сервісу повідомлень
// Доступний лише в приватній мережі
var app = WebApplication.Create(args);
app.MapPost("/internal/notifications/send",
(NotificationRequest req) =>
{
// Немає зовнішньої автентифікації —
// довіряємо мережевому контуру
return Results.Ok(new { sent = true });
});
app.Run();
Характеристики:
- Менше уваги документації — розробники обох сторін сидять в одному офісі
- Можна використовувати бінарні протоколи (gRPC) для максимальної продуктивності
- Оновлення без довгого циклу deprecation — контролюєте обидва боки
Партнерське API (Partner API)
Надається обмеженому колу зовнішніх компаній-партнерів за договором.
// Партнерське API для B2B інтеграції
var app = WebApplication.Create(args);
app.MapGet("/v1/partners/{partnerId}/orders",
(string partnerId, HttpContext ctx) =>
{
// Перевірка API-ключа партнера
var apiKey = ctx.Request.Headers["X-Partner-ApiKey"]
.FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
return Results.Unauthorized();
// Повернення замовлень лише цього партнера
return Results.Ok(new {
partner_id = partnerId,
orders = new[] {
new { id = 1, status = "completed" }
}
});
});
app.Run();
Характеристики:
- Обов'язкова аутентифікація (API-ключі, OAuth)
- Детальна документація та підтримка
- Версіонування з довгим циклом deprecation
Публічне API (Public / Open API)
Доступне будь-якому розробнику в Інтернеті. Це те, з чим ви найчастіше будете працювати.
// Публічне API для мобільного додатку
var app = WebApplication.Create(args);
app.MapGet("/v1/recipes", () =>
{
// Будь-хто може отримати список рецептів
return Results.Ok(new[]
{
new { id = "lungo", title = "Лунго", volume = "250ml" },
new { id = "americano", title = "Американо", volume = "350ml" }
});
});
app.MapPost("/v1/orders", (OrderRequest order) =>
{
// Створення замовлення вимагає авторизації
return Results.Created($"/v1/orders/{42}", new { id = 42 });
});
app.Run();
record OrderRequest(string Recipe, string CoffeeMachineId);
Характеристики:
- Максимально детальна документація (OpenAPI/Swagger)
- Суворе версіонування та зворотна сумісність
- Rate limiting, автентифікація, захист від зловживань
- JSON-over-HTTP — вибір за замовчуванням, оскільки ця технологія зрозуміла максимально широкому колу програмістів і дозволяє розробляти клієнтські додатки практично на будь-якій платформі
5. Від бібліотечного API до мережевого API
Термін «API» з'явився задовго до вебу. Спочатку він означав інтерфейс бібліотеки — набір функцій, які можна викликати з коду:
// Бібліотечне API — виклик функції напряму
var result = Math.Sqrt(144); // 12
З розвитком Інтернету та розподілених систем виникла потреба викликати функції на іншому комп'ютері, через мережу. Так з'явилися мережеві API (Network API або Web API).
Принципова різниця:
| Аспект | Бібліотечне API | Мережеве API |
|---|---|---|
| Виклик | Прямий (в межах процесу) | Через мережу (HTTP, gRPC) |
| Швидкість | Наносекунди | Мілісекунди (мережева затримка) |
| Надійність | Гарантована (якщо код працює) | Мережа може впасти в будь-який момент |
| Формат даних | Нативні типи мови | Серіалізація (JSON, Protobuf) |
| Версіонування | Через NuGet/npm версії | Через URL або заголовки |
6. Навіщо вивчати дизайн API?
Може здатися: «Навіщо окремий модуль для API? Достатньо написати кілька ендпоінтів і все працює». Але ось сценарій із реального життя:
Понеділок: «Все просто»
Ви створюєте один ендпоінт: GET /orders — повертає список замовлень. Все працює.
Вівторок: «А як фільтрувати?»
Фронтенд-розробник просить додати фільтр за статусом: GET /orders?status=active. Додаєте — працює.
Середа: «А як шукати по кількох рецептах?»
Потрібно шукати замовлення для лунго і латте одночасно. GET /orders?recipe=lungo&recipe=latte? Але стандарту передачі масивів у URL не існує. Доводиться вигадувати: recipe=lungo,latte? Чи recipe[]=lungo&recipe[]=latte? Кожен фреймворк обробляє це по-різному.
Четвер: «Дані не оновлюються!»
Клієнт кешував GET /orders, і тепер показує застарілі дані. Потрібна політика кешування: Cache-Control, ETag, If-None-Match.
П'ятниця: «Замовлення створюється двічі!»
Мережа обірвалась під час POST /orders. Клієнт повторив запит — і створив дублікат замовлення. Потрібен токен ідемпотентності.
Кожна з цих проблем має відомі та перевірені рішення. Саме їх ми й вивчатимемо в цьому модулі.
7. Що нас чекає: Структура модуля
Цей модуль побудований за принципом «від простого до складного». Кожна наступна тема спирається на попередню:
Протягом усього модуля ми будемо використовувати один наскрізний приклад — API сервісу замовлення кави. Цей приклад дозволяє продемонструвати всі паттерни: від простого CRUD до складних сценаріїв синхронізації та обробки помилок.
8. Практичні завдання
Рівень 1: Базовий
Для кожного з наведених сценаріїв визначте, який тип API (внутрішнє, партнерське, публічне) найкраще підходить. Обґрунтуйте вибір.
- Мікросервіс обробки платежів спілкується з мікросервісом інвентаризації
- Сервіс доставки їжі надає API для ресторанів-партнерів
- Погодний сервіс, доступний будь-якому розробнику після реєстрації
- Сервіс аналітики, який збирає дані з 5 внутрішніх мікросервісів
Для кожного з наведених компонентів визначте, чи виконує він роль клієнта, сервера, чи обох одночасно:
- Мобільний додаток для замовлення кави
- API-гейтвей, що маршрутизує запити між мікросервісами
- Сервіс, який за cron-розкладом опитує зовнішній API погоди і зберігає дані в базу
- Браузер, що відкриває вебсайт
Рівень 2: Аналітичний
Придумайте власну аналогію для API з реального світу (не ресторан/офіціант — ця аналогія вже використана). Опишіть, що в вашій аналогії є:
- Клієнт
- Сервер
- API (контракт)
- Запит
- Відповідь
- Помилка
Оберіть один з публічних API (наприклад, GitHub API, JSONPlaceholder або OpenWeatherMap) і дайте відповідь:
- Який формат даних використовується?
- Яка стратегія версіонування?
- Як організована аутентифікація?
- Яка структура URL — чи видно ієрархію ресурсів?
Рівень 3: Проєктування
::accordion-item{label="Завдання 3.1: Спроєктуйте API "з нуля"" icon="i-lucide-circle-help"} Уявіть, що ви проєктуєте API для сервісу бронювання кімнат переговорів в офісі. Визначте:
- Які ресурси (сутності) потрібні? (мінімум 3)
- Які операції доступні для кожного ресурсу?
- Хто є клієнтами API? (мінімум 2 типи)
- Який тип API це буде (внутрішнє/партнерське/публічне)?
- Напишіть 3–5 прикладів URL-адрес ваших ендпоінтів
Це завдання — перший крок до створення повноцінної специфікації, яку ми навчимося писати в останній статті модуля.
::
9. Резюме
API — це контракт
Клієнт ≠ Сервер
Тип визначає дизайн
Дизайн API — інженерна дисципліна
Далі: у наступній статті ми розберемо формати даних — JSON, XML, TOML та бінарні формати. Навчимося обирати правильний формат і розберемо стратегії стиснення для оптимізації трафіку.
Структура проєкту: від хаосу до архітектури
Еволюція організації Minimal API проєкту: від одного файлу до Extension Methods, Route Groups, Feature Folders та Vertical Slice Architecture.
Формати даних: JSON, XML, TOML та бінарні формати
Глибокий розбір форматів передачі даних у HTTP API: синтаксис JSON, порівняння з XML та TOML, бінарні формати (Protobuf, FlatBuffers), стратегії стиснення (gzip, brotli, deflate).