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

Что такое REST?

1.3 Junior🔥 211 комментариев
#REST API и HTTP

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

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

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

REST (Representational State Transfer)

REST — это архитектурный стиль для проектирования распределённых систем и веб-сервисов. Он описывает, как строить масштабируемые веб-приложения, используя уже существующие стандарты HTTP и веб-протоколов.

Основные принципы REST

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

  • Клиент отделён от сервера
  • Могут развиваться независимо, пока интерфейс остаётся согласованным

2. Statelessness (отсутствие состояния)

  • Каждый запрос содержит всю информацию, необходимую серверу для его обработки
  • Сервер не хранит информацию о состоянии клиента между запросами
  • Это делает систему масштабируемой, так как сервер не требует сохранения сессий

3. Ресурсы как центральная концепция

  • Данные представляются как ресурсы (пользователи, статьи, комментарии)
  • Каждый ресурс имеет уникальный идентификатор (URL/URI)
  • Пример: /api/v1/users/123, /api/v1/posts/456

4. Стандартные методы HTTP

  • GET — получить ресурс (безопасно, идемпотентно)
  • POST — создать новый ресурс
  • PUT — полное обновление ресурса (идемпотентно)
  • PATCH — частичное обновление ресурса
  • DELETE — удалить ресурс (идемпотентно)

5. Представления (Representation)

  • Ресурсы передаются в разных форматах: JSON, XML, HTML
  • Клиент указывает нужный формат через заголовок Accept
  • Сервер выбирает подходящее представление

6. Кэшируемость

  • Ответы должны определять, кэшируются ли они
  • Улучшает производительность и масштабируемость

Примеры REST API на Python

# Пример с Flask
from flask import Flask, request, jsonify

app = Flask(__name__)

# In-memory storage для примера
users = {
    1: {"id": 1, "name": "Alice", "email": "alice@example.com"},
    2: {"id": 2, "name": "Bob", "email": "bob@example.com"},
}

# GET все пользователи
@app.get("/api/v1/users")
def get_users():
    return jsonify(list(users.values()))

# GET конкретного пользователя
@app.get("/api/v1/users/<int:user_id>")
def get_user(user_id):
    user = users.get(user_id)
    if not user:
        return jsonify({"error": "User not found"}), 404
    return jsonify(user)

# POST создание нового пользователя
@app.post("/api/v1/users")
def create_user():
    data = request.get_json()
    new_id = max(users.keys()) + 1 if users else 1
    new_user = {"id": new_id, **data}
    users[new_id] = new_user
    return jsonify(new_user), 201

# PUT полное обновление
@app.put("/api/v1/users/<int:user_id>")
def update_user(user_id):
    if user_id not in users:
        return jsonify({"error": "User not found"}), 404
    data = request.get_json()
    users[user_id] = {"id": user_id, **data}
    return jsonify(users[user_id])

# PATCH частичное обновление
@app.patch("/api/v1/users/<int:user_id>")
def patch_user(user_id):
    if user_id not in users:
        return jsonify({"error": "User not found"}), 404
    data = request.get_json()
    users[user_id].update(data)
    return jsonify(users[user_id])

# DELETE удаление
@app.delete("/api/v1/users/<int:user_id>")
def delete_user(user_id):
    if user_id not in users:
        return jsonify({"error": "User not found"}), 404
    deleted = users.pop(user_id)
    return jsonify({"message": "User deleted", "user": deleted})

if __name__ == "__main__":
    app.run(debug=True)

Примеры с FastAPI (более современный подход)

from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from typing import List

app = FastAPI()

class User(BaseModel):
    id: int | None = None
    name: str
    email: str

users_db = [
    {"id": 1, "name": "Alice", "email": "alice@example.com"},
    {"id": 2, "name": "Bob", "email": "bob@example.com"},
]

@app.get("/api/v1/users", response_model=List[User])
def list_users():
    return users_db

@app.get("/api/v1/users/{user_id}", response_model=User)
def get_user(user_id: int):
    user = next((u for u in users_db if u["id"] == user_id), None)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return user

@app.post("/api/v1/users", response_model=User, status_code=status.HTTP_201_CREATED)
def create_user(user: User):
    new_id = max(u["id"] for u in users_db) + 1 if users_db else 1
    new_user = {**user.dict(), "id": new_id}
    users_db.append(new_user)
    return new_user

@app.put("/api/v1/users/{user_id}", response_model=User)
def update_user(user_id: int, user: User):
    idx = next((i for i, u in enumerate(users_db) if u["id"] == user_id), None)
    if idx is None:
        raise HTTPException(status_code=404, detail="User not found")
    updated = {**user.dict(), "id": user_id}
    users_db[idx] = updated
    return updated

@app.delete("/api/v1/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int):
    global users_db
    if not any(u["id"] == user_id for u in users_db):
        raise HTTPException(status_code=404, detail="User not found")
    users_db = [u for u in users_db if u["id"] != user_id]

HTTP статус-коды в REST

  • 200 OK — успешный GET, PUT, PATCH
  • 201 Created — успешный POST
  • 204 No Content — успешный DELETE
  • 400 Bad Request — ошибка валидации
  • 401 Unauthorized — нет аутентификации
  • 403 Forbidden — нет прав доступа
  • 404 Not Found — ресурс не найден
  • 409 Conflict — конфликт (например, дублирование)
  • 500 Internal Server Error — ошибка сервера

Преимущества REST

✅ Простота и понятность ✅ Использует стандартные HTTP методы ✅ Масштабируемость (stateless) ✅ Кэшируемость ✅ Разделение клиента и сервера

Когда REST может быть неудачным выбором

❌ Real-time приложения (лучше WebSockets) ❌ Сложные запросы с глубокой фильтрацией (рассмотреть GraphQL) ❌ Высоконагруженные системы с частыми обновлениями

REST остаётся стандартом де-факто для веб-приложений благодаря своей простоте, масштабируемости и универсальности.