← Назад к вопросам

Расшифруй аббревиатуру REST

2.2 Middle🔥 251 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

REST: Representational State Transfer

REST расшифровывается как "Representational State Transfer" — архитектурный стиль для построения веб-сервисов.

Хотя аббревиатура звучит сложно, концепция очень простая: веб-сервис работает как набор ресурсов, которыми манипулируют с помощью стандартных HTTP методов.

Три ключевых компонента

1. Representational (Представление)

Ресурс представлен в определённом формате:

  • JSON (самый популярный сейчас)
  • XML (устаревший, но всё ещё используется)
  • HTML
  • Plain text
# Один ресурс User может быть представлен как:
# JSON
{
    "id": 1,
    "name": "Alice",
    "email": "alice@example.com"
}

# XML
<user>
    <id>1</id>
    <name>Alice</name>
    <email>alice@example.com</email>
</user>

2. State (Состояние)

Клиент и сервер обмениваются представлениями состояния ресурса:

  • Каждый запрос содержит ВСЮ информацию для обработки
  • Сервер НЕ хранит состояние клиента между запросами (stateless)
  • Следующий запрос независим от предыдущего
# Запрос 1: получаем текущее состояние
GET /api/v1/users/1
# Ответ: полное представление User

# Запрос 2: обновляем состояние
PUT /api/v1/users/1
{
    "name": "Alice Updated",
    "email": "alice.new@example.com"
}
# Ответ: новое полное представление User

3. Transfer (Передача)

Передача состояния происходит через HTTP протокол:

  • GET — получить представление
  • POST — создать новый ресурс
  • PUT/PATCH — обновить существующий
  • DELETE — удалить ресурс

REST в действии: Пример

# FastAPI приложение — идеально для REST
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    id: int
    name: str
    email: str

# 1. GET — получить все ресурсы (представление коллекции)
@app.get("/users")
async def list_users():
    # Представление: список всех пользователей
    return [
        {"id": 1, "name": "Alice", "email": "alice@example.com"},
        {"id": 2, "name": "Bob", "email": "bob@example.com"},
    ]

# 2. GET — получить один ресурс (представление одного)
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Представление: один пользователь
    return {"id": user_id, "name": "Alice", "email": "alice@example.com"}

# 3. POST — создать новый ресурс (отправляем представление нового состояния)
@app.post("/users")
async def create_user(user: User):
    # Создаём новый ресурс с переданным представлением
    user.id = 3  # Сервер генерирует ID
    return user

# 4. PUT — обновить весь ресурс (отправляем новое полное представление)
@app.put("/users/{user_id}")
async def update_user(user_id: int, user: User):
    # Заменяем ВСЁ представление пользователя
    user.id = user_id
    return user

# 5. PATCH — обновить часть ресурса (отправляем только изменения)
@app.patch("/users/{user_id}")
async def partial_update(user_id: int, data: dict):
    # Обновляем только переданные поля
    return {"id": user_id, "name": data.get("name"), ...}

# 6. DELETE — удалить ресурс
@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    # Удаляем ресурс, ничего не возвращаем (204 No Content)
    return {}

REST принципы (RFC 7231)

1. Клиент-Сервер архитектура

Клиент                    Сервер
   |                        |
   |------ HTTP GET -------->|
   |                      (обработка)
   |<---- JSON/XML ---------|

2. Stateless (без состояния)

# ❌ Плохо: сервер запомнил пользователя
logged_in_users = {}

@app.post("/login")
def login(user: str):
    logged_in_users[user] = True  # Запомнили в памяти
    return {"status": "logged in"}

# ✅ Хорошо: каждый запрос содержит токен
@app.get("/profile")
def get_profile(token: str):  # Токен в каждом запросе
    user = verify_token(token)
    return {"profile": ...}

3. Кэшируемость (Cacheable)

# Ответы помечаются как кэшируемые или нет
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Эта операция идемпотентна (всегда один результат)
    # Браузер может кэшировать результат
    return {"id": user_id, "name": "Alice"}

# HTTP заголовок:
# Cache-Control: max-age=3600  (кэшировать на час)

4. Единообразный интерфейс

Одинаковый способ работы со всеми ресурсами:

GET /users         — список
GET /users/1       — один
POST /users        — создать
PUT /users/1       — обновить
DELETE /users/1    — удалить

GET /products      — список
GET /products/5    — один
POST /products     — создать
PUT /products/5    — обновить
DELETE /products/5 — удалить

REST коды ответов (HTTP статусы)

КодСмыслПример
200 OKУспешноGET user вернул данные
201 CreatedСозданоPOST создал новый ресурс
204 No ContentУспешно, но ничегоDELETE удалил
400 Bad RequestОшибка клиентаНеверный JSON
404 Not FoundНе найденоGET несуществующий ID
500 Server ErrorОшибка сервераCrash в обработчике

Пример: Полная REST API для блога

from fastapi import FastAPI, HTTPException
from typing import List

app = FastAPI()

class Post(BaseModel):
    id: int
    title: str
    content: str
    author: str

posts_db = {}

# СПИСОК постов
@app.get("/posts")
async def list_posts() -> List[Post]:
    return list(posts_db.values())

# ОДИН пост
@app.get("/posts/{post_id}")
async def get_post(post_id: int) -> Post:
    if post_id not in posts_db:
        raise HTTPException(status_code=404, detail="Post not found")
    return posts_db[post_id]

# СОЗДАТЬ пост
@app.post("/posts")
async def create_post(post: Post) -> Post:
    posts_db[post.id] = post
    return post

# ОБНОВИТЬ пост
@app.put("/posts/{post_id}")
async def update_post(post_id: int, post: Post) -> Post:
    if post_id not in posts_db:
        raise HTTPException(status_code=404, detail="Post not found")
    post.id = post_id
    posts_db[post_id] = post
    return post

# УДАЛИТЬ пост
@app.delete("/posts/{post_id}")
async def delete_post(post_id: int):
    if post_id not in posts_db:
        raise HTTPException(status_code=404, detail="Post not found")
    del posts_db[post_id]
    return {"status": "deleted"}

REST vs SOAP vs GraphQL

ХарактеристикаRESTSOAPGraphQL
ПростотаПростоСложноСредне
ГибкостьСредняяСредняяВысокая
КэшированиеВстроено в HTTPНетНет
ВыучиваниеБыстроМедленноМедленно
Использование90% современных APIЛегасиНовые проекты

Важные замечания

1. REST — не база данных

# ❌ Неправильное название
GET /api/v1/getUserById?id=1  # Глагол (неправильно)
GET /api/v1/users?id=1         # Существительное (правильно)

GET /api/v1/createUser         # Глагол (неправильно)
POST /api/v1/users             # HTTP метод + существительное (правильно)

2. REST требует правильных HTTP методов

# ❌ Плохо: всё через GET
GET /api/delete_user?id=1

# ✅ Хорошо: используй DELETE
DELETE /api/users/1

3. Версионирование API

# Версия в пути (популярный способ)
GET /api/v1/users      # старая версия
GET /api/v2/users      # новая версия

# Версия в заголовке (более чистый способ)
GET /api/users
Accept-Version: 2.0

Вывод

REST — архитектурный стиль, где:

  • Всё — ресурсы (существительные)
  • Операции — HTTP методы (GET, POST, PUT, DELETE)
  • Общение — Representation (JSON, XML)
  • Сервер — Stateless (не запоминает клиентов)

Это сделало веб стандартным и простым для всех разработчиков.