🌐 Раздел 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 multiplexing, строгая кодогенерация. Высоконагруженная микросервисная сеть с жесткими требованиями к latency (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 строго запрещает хранение клиентской сессии на сервере.

Связанные темы