🌐 Розділ 6 · Питання #1

Що таке REST

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


🟢 Junior Level

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

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

Ключові поняття REST

  1. Ресурс (Resource): Будь-яка сутність у системі, до якої можна звернутися (користувач, замовлення, товар). Ресурс завжди має унікальний ідентифікатор — URI (наприклад, /api/v1/orders/42).
  2. Представлення (Representation): Поточний стан ресурсу, переданий у певному форматі даних (зазвичай JSON, рідше XML).
  3. Стандартні методи HTTP: Операції над ресурсами виражаються через дієслова протоколу HTTP:
    • GET — читання ресурсу (безпечний та ідемпотентний).
    • POST — створення нового ресурсу (неідемпотентний).
    • PUT — повна заміна ресурсу (ідемпотентний).
    • PATCH — часткове оновлення ресурсу (як правило, неідемпотентний).
    • DELETE — видалення ресурсу (ідемпотентний).
  4. Статус-коди HTTP: Сервер повідомляє про результат операції стандартними тризначними кодами (200 OK, 201 Created, 400 Bad Request, 404 Not Found, 500 Internal Server Error).

Базовий приклад REST-контролера на Spring Boot 3

package com.example.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    // GET /api/v1/users — отримати список ресурсів
    @GetMapping
    public List<UserResponseDto> getAllUsers() {
        return userService.findAll();
    }

    // GET /api/v1/users/{id} — отримати конкретний ресурс
    @GetMapping("/{id}")
    public ResponseEntity<UserResponseDto> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    // POST /api/v1/users — створити ресурс
    @PostMapping
    public ResponseEntity<UserResponseDto> createUser(@RequestBody CreateUserRequest request) {
        UserResponseDto created = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(created); // 201 Created
    }

    // DELETE /api/v1/users/{id} — видалити ресурс
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT) // 204 No Content
    public void deleteUser(@PathVariable Long id) {
        userService.deleteById(id);
    }
}

🟡 Middle Level

6 архітектурних обмежень REST (Constraints)

Щоб API вважався істинно RESTful, він зобов’язаний задовольняти 6 суворим правилам:

1. Client-Server (Розподіл відповідальності інтерфейсу та сховища)
2. Stateless (Відсутність стану сесії клієнта на сервері)
3. Cacheable (Явний контроль кешування відповідей клієнтом і проксі)
4. Layered System (Багаторівнева система: балансувальники, CDN, шлюзи прозорі)
5. Uniform Interface (Одноманітний інтерфейс — фундамент REST)
6. Code on Demand (Опціонально: передача виконуваного коду, наприклад JS)
  1. Client-Server (Клієнт-Сервер): Повне розділення інтерфейсу користувача (Frontend, Mobile) та бізнес-логіки/сховища (Backend). Вони можуть еволюціонувати та масштабуватися незалежно.
  2. Stateless (Без збереження стану): Сервер не зберігає контекст сесії клієнта між запитами. Кожен запит зобов’язаний містити абсолютно всю інформацію для його авторизації та обробки (наприклад, JWT-токен у заголовку Authorization).
  3. Cacheable (Кешованість): Кожна відповідь зобов’язана явно оголошувати, чи можна її кешувати і на який термін (заголовки Cache-Control, ETag, Last-Modified), виключаючи повторні важкі запити.
  4. Layered System (Багаторівнева архітектура): Клієнт не знає, чи спілкується він безпосередньо з сервером додатків, чи з проміжною ланкою (Reverse Proxy, Load Balancer, API Gateway, CDN). Проміжні шари можуть забезпечувати безпеку та кешування без зміни контракту.
  5. Uniform Interface (Одноманітний інтерфейс): Найсуворіше та найголовніше обмеження REST, що складається з 4 постулатів:
    • Ідентифікація ресурсів: Ресурси відокремлені від їхніх представлень і мають стабільні URI (/products/123).
    • Маніпуляція через представлення: Клієнт передає представлення (JSON) та бажану дію через HTTP-метод.
    • Самодостатні повідомлення (Self-descriptive messages): Кожен запит/відповідь містить метадані про формат (Content-Type: application/json), кодування та кешування.
    • HATEOAS (Hypermedia As The Engine Of Application State): Відповідь сервера містить гіперпосилання на доступні подальші дії клієнта.
  6. Code on Demand (Код на вимогу, опціональне): Сервер може передавати клієнту виконуваний код для тимчасового розширення функціональності (наприклад, JavaScript-сценарії або WebAssembly).

Модель зрілості Річардсона (Richardson Maturity Model)

Леонард Річардсон запропонував класифікацію вебсервісів за ступенем їхньої відповідності принципам REST:

Level 3: HATEOAS (Істинний RESTful API)
    ▲
Level 2: HTTP Verbs & Status Codes (Золотий стандарт індустрії / Pragmatic REST)
    ▲
Level 1: Ресурси (Кожен ресурс має свій URI: /orders, /users)
    ▲
Level 0: The Swamp of POX (Один URI, один HTTP-метод, RPC over HTTP, наприклад SOAP або XML-RPC)
  • Level 0: Використання HTTP як простого транспорту. Усі запити йдуть методом POST на один ендпоінт /api/service, а дія зашита в тіло повідомлення.
  • Level 1 (Resources): Поява унікальних URI для сутностей (/users/1, /orders), але операції все ще можуть виконуватися одним методом POST.
  • Level 2 (HTTP Verbs & Codes): Коректне використання семантики HTTP: методи GET, POST, PUT, DELETE та статус-коди 200, 201, 404, 500. Це рівень 99% комерційних «REST API».
  • Level 3 (HATEOAS): Сервер разом із даними повертає посилання на пов’язані дії (_links). Повна відповідність баченню Роя Філдінга.

🔴 Senior Level

REST vs Альтернативи: Коли REST є поганим вибором

У сучасній enterprise-архітектурі REST не є срібною кулею:

Технологія Де перевершує REST Коли обирати замість REST
gRPC (Protocol Buffers) Міжсервісна взаємодія (East-West traffic). Бінарна серіалізація в 5–10 разів швидша за JSON, мультиплексування HTTP/2, сувора кодогенерація. Високонавантажена мікросервісна мережа із жорсткими вимогами до затримок (SLA < 10ms).
GraphQL Вирішує проблеми Over-fetching (зайві поля) та Under-fetching (N+1 HTTP-запитів до різних ресурсів). Клієнт сам запитує схему. Складні клієнтські додатки (BFF, Web/Mobile), що вимагають агрегації сотень різнорідних сутностей.
WebSockets / RSocket Двонапрямлений постійний повнодуплексний обмін повідомленнями з мінімальним оверхедом заголовків. Real-time чати, котирування бірж, дашборди з живими графіками, IoT телеметрія.

Сучасний стандарт обробки помилок: RFC 9457 (Problem Details)

У Spring Boot 3+ стандартизовано універсальний формат повідомлень про помилки REST API:

package com.example.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.URI;
import java.time.Instant;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ProblemDetail handleUserNotFound(UserNotFoundException ex) {
        // Формування стандартного Problem Details (RFC 9457)
        ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
                HttpStatus.NOT_FOUND, ex.getMessage()
        );
        problemDetail.setTitle("User Not Found");
        problemDetail.setType(URI.create("https://api.example.com/errors/not-found"));
        problemDetail.setProperty("timestamp", Instant.now());
        problemDetail.setProperty("errorCode", "USR-404");
        return problemDetail;
    }
}

Клієнт отримує стандартизований JSON:

{
  "type": "https://api.example.com/errors/not-found",
  "title": "User Not Found",
  "status": 404,
  "detail": "User with id 42 does not exist",
  "instance": "/api/v1/users/42",
  "timestamp": "2026-09-26T12:00:00Z",
  "errorCode": "USR-404"
}

Highload-оптимізації REST на Java 21+

  1. Virtual Threads (Project Loom у Java 21):
    • Увімкнення spring.threads.virtual.enabled=true переводить вбудований Tomcat на віртуальні потоки.
    • Зникає потреба переписувати сервіси на реактивний стек (Spring WebFlux) лише заради утримання 50 000 паралельних I/O з’єднань.
  2. HTTP Caching з ETag (ShallowEtagHeaderFilter):
    • Сервер розраховує MD5-хеш тіла відповіді та віддає заголовок ETag: "686897696a7c76".
    • Клієнт при повторному запиті відправляє If-None-Match: "686897696a7c76".
    • Сервер миттєво повертає 304 Not Modified з порожнім тілом, заощаджуючи вихідний трафік та час рендерингу.

🎯 Шпаргалка для інтерв’ю

30-секундна відповідь

REST — це архітектурний стиль побудови вебсервісів поверх протоколу HTTP, сформульований Роєм Філдінгом у 2000 році.

  • Базується на 6 обмеженнях: Client-Server, Stateless, Cacheable, Layered System, Uniform Interface та Code on Demand.
  • У центрі концепції знаходиться Ресурс, ідентифікований URI. Операції над ресурсами задаються дієсловами HTTP (GET, POST, PUT, PATCH, DELETE), а стан передається через формати представлень (JSON/XML).
  • За моделлю зрілості Річардсона більшість production API знаходяться на Level 2 (використання ресурсів, HTTP-дієслів та статус-кодів). Справжній Level 3 вимагає підтримки HATEOAS.

4 каверзних питання з відповідями

  1. Чи є REST протоколом або специфікацією? Відповідь: Ні, REST — це архітектурний стиль (набір принципів та обмежень). Протоколом є HTTP, поверх якого зазвичай реалізується REST. Стандартом чи специфікацією REST не є, тому розробники можуть адаптувати його під власні потреби (Pragmatic REST).

  2. Що таке Uniform Interface (Одноманітний інтерфейс) і з яких 4 частин він складається? Відповідь: Це центральне обмеження REST, що відділяє архітектуру від інших стилів (RPC). Воно включає:
    1. Ідентифікацію ресурсів через URI.
    2. Маніпуляцію ресурсами через представлення (клієнт змінює ресурс, відправляючи JSON).
    3. Самоописувані повідомлення (наявність метаданих: Content-Type, заголовки кешування).
    4. HATEOAS (сервер передає гіперпосилання на доступні подальші переходи стану).
  3. У чому різниця між RESTful API та звичайним HTTP API? Відповідь: HTTP API просто використовує протокол HTTP як транспорт для передачі даних (часто як RPC, Level 0–1 за Річардсоном). RESTful API суворо дотримується всіх 6 обмежень стилю REST, включно зі statelessness, семантикою HTTP-дієслів, кешуванням та гіпермедіа (HATEOAS).

  4. Коли REST архітектурно програє іншим підходам? Відповідь:
    1. У міжсервісній взаємодії мікросервісів з високими навантаженнями — gRPC значно швидший через бінарний формат Protobuf та мультиплексування HTTP/2.
    2. При складній вибірці пов’язаних сутностей для мобільних клієнтів — GraphQL вирішує проблеми Over-fetching та множинних запитів.
    3. Для real-time даних — WebSockets та RSocket перевершують REST, усуваючи оверхед на постійне відкриття HTTP-з’єднань.

Червоні прапорці (чого категорично не можна говорити)

  • ❌ «REST — це офіційний протокол передачі даних W3C» — це архітектурний стиль дисертації, а не протокол.
  • ❌ «Метод GET можна використовувати для видалення запису з бази» — грубе порушення REST: метод GET зобов’язаний бути безпечним (Safe) і не мати побічних ефектів.
  • ❌ «REST вимагає обов’язкового використання формату JSON» — REST не прив’язаний до JSON, він працює з будь-якими представленнями (XML, HTML, Protocol Buffers, MessagePack).
  • ❌ «Сервер REST зберігає стан сесії користувача в оперативній пам’яті» — обмеження Stateless суворо забороняє зберігання клієнтської сесії на сервері.

Пов’язані теми