В чем разница между REST и REST API?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отлично, это классический и важный вопрос на собеседовании, который проверяет понимание основ веб-разработки. Часто эти термины используют как синонимы, но это неточно. Как Go Developer с опытом, я объясню разницу четко и структурно.
Основные определения
REST (Representational State Transfer)
Это архитектурный стиль (не стандарт и не протокол), предложенный Ройем Филдингом в 2000 году. REST описывает набор ограничений (constraints), которые нужно соблюдать для создания масштабируемых, производительных и надежных распределенных систем (веб-сервисов). Это абстрактная теория.
REST API (Application Programming Interface)
Это конкретная реализация API, которая следует принципам REST. Это практический инструмент, с которым работают разработчики каждый день. Когда мы говорим "сделай REST API для пользователей", мы имеем в виду "создай HTTP-интерфейс, который следует ограничениям REST".
Сравнительная таблица
| Критерий | REST (архитектурный стиль) | REST API (конкретная реализация) |
|---|---|---|
| Сущность | Абстрактная теория, набор из 6 ключевых ограничений. | Практический код, набор эндпоинтов (URL), методов, форматов данных. |
| Уровень | Высокоуровневые принципы проектирования системы в целом. | Низкоуровневая реализация: роуты, хендлеры, сериализаторы. |
| Обязательность | Применяется ко всей системе (серверы, клиенты, промежуточные узлы). | Применяется к конкретному интерфейсу взаимодействия между клиентом и сервером. |
| Пример | "Используйте кэширование", "Будь безсостоятельным (stateless)". | GET /api/v1/users/, POST /api/v1/users/ с заголовком Content-Type: application/json. |
Ключевые ограничения REST (что должно быть в REST API)
Чтобы API можно было назвать RESTful, оно должно неукоснительно следовать всем шести ограничениям:
- Клиент-серверная архитектура: Разделение Concerns. CLI-приложение и веб-интерфейс используют один бэкенд.
- Безсостоятельность (Statelessness): Каждый запрос от клиента должен содержать всю информацию для его обработки. Сервер не хранит сессию клиента между запросами. На практике в Go это значит, что мы не используем глобальные переменные или встроенную в сервер сессию для хранения данных пользователя. Авторизация — через токен в заголовке (
Authorization: Bearer ...). - Кэшируемость: Ответы должны явно или неявно помечаться как кэшируемые/некэшируемые. Это снижает нагрузку.
- Единообразие интерфейса (Uniform Interface): Самый важный и часто нарушаемый принцип. Он включает:
* **Идентификация ресурсов:** У каждого ресурса (пользователь, заказ) есть уникальный идентификатор (URI), например `/users/123`.
* **Манипуляция ресурсами через представления:** Клиент получает достаточно данных (представление, например JSON), чтобы изменить или удалить ресурс.
* **Самоописательные сообщения:** Каждый запрос/ответ содержит enough информацию для его обработки (метод, `Content-Type`, `Accept`).
* **Гипермедийные связи (HATEOAS):** В ответе должны быть ссылки на связанные действия (`self`, `next`, `delete`). Часто игнорируется в "псевдо-REST" API.
- Слоистая система: Клиент не должен знать, подключается ли он к серверу напрямую или через балансировщик, шлюз, кэш.
- Код по требованию (опционально): Сервер может временно расширять функциональность клиента, отправив ему исполняемый код (JavaScript). На практике почти не используется.
Практический пример на Go: REST vs. "RPC over HTTP"
// ПЛОХОЙ ПРИМЕР: RPC-style over HTTP (НЕ соответствует REST!)
// Здесь эндпоинт — это действие ("getUser"), а не ресурс.
// Урушает принцип единообразия интерфейса.
func getUserHandler(w http.ResponseWriter, r *http.Request) {
// Логика получения пользователя
// ...
// URI: /api/getUser?id=123
// Метод: GET (но по смыслу ближе к RPC)
}
// ХОРОШИЙ ПРИМЕР: RESTful на Go (идолологически чистый)
// Ресурс "users", идентифицируемый по URI.
// Действие определено HTTP-методом.
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// GET /api/v1/users/123
// Возвращаем представление ресурса "user"
userID := chi.URLParam(r, "id")
// ... логика получения по ID
case http.MethodPost:
// POST /api/v1/users
// Создание нового ресурса
// ... логика создания
case http.MethodPut:
// PUT /api/v1/users/123
// Полное обновление ресурса
case http.MethodDelete:
// DELETE /api/v1/users/123
// Удаление ресурса
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
// В ответе на GET /api/v1/users/123 (HATEOAS):
// {
// "id": 123,
// "name": "Ivan",
// "_links": {
// "self": { "href": "/api/v1/users/123" },
// "orders": { "href": "/api/v1/users/123/orders" }
// }
// }
Вывод для собеседования
Кратко: REST — это "Конституция" для проектирования веб-систем. REST API — это "Закон", принятый на основе этой Конституции.
На практике в индустрии (и в 90% вакансий):
Когда работодатель пишет "нужен опыт с REST API", он почти всегда имеет в виду использование HTTP-методов (GET/POST/PUT/DELETE) semantically и ресурсо-ориентированные URI (/resources/{id}), а не строгое следование всем шести ограничениям (особенно HATEOAS).
Что важно показать на интервью:
- Понимать разницу между архитектурным стилем и его реализацией.
- Четко знать 6 ограничений REST и уметь объяснить 2-3 ключевых (особенно stateless и uniform interface).
- Привести пример "правильного" и "неправильного" URI/метода на Go.
- Упомянуть, что JSON API или OpenAPI (Swagger) — это форматы/спецификации, которые помогают описать REST API, но сами по себе не делают API RESTful.
- Осознавать, что в мире Go часто используют go-chi или gin для создания RESTful-роутеров, а Encoding/JSON или json-iterator/go для сериализации, что технически упрощает следование принципам REST.
Именно такое глубинное понимание, а не заученные фразы, отличает Go Developer уровня Senior от Junior.