\n```\n\n### HTTP методы и их использование\n\n```python\nfrom fastapi import FastAPI, status\n\napp = FastAPI()\n\n# GET - безопасен, идемпотентен, кэшируется\n@app.get(\"/users\")\ndef list_users():\n \"\"\"Получить всех пользователей\"\"\"\n return []\n\n# POST - не идемпотентен, создает новые ресурсы\n@app.post(\"/users\", status_code=status.HTTP_201_CREATED)\ndef create_user(user: dict):\n \"\"\"Создать нового пользователя\"\"\"\n return {\"id\": 1, **user}\n\n# PUT - идемпотентен, заменяет весь ресурс\n@app.put(\"/users/{user_id}\")\ndef replace_user(user_id: int, user: dict):\n \"\"\"Полностью заменить пользователя\"\"\"\n return {\"id\": user_id, **user}\n\n# PATCH - не идемпотентен, обновляет части ресурса\n@app.patch(\"/users/{user_id}\")\ndef update_user(user_id: int, updates: dict):\n \"\"\"Обновить часть пользователя\"\"\"\n return {\"id\": user_id, \"name\": \"Updated\"}\n\n# DELETE - идемпотентен\n@app.delete(\"/users/{user_id}\", status_code=status.HTTP_204_NO_CONTENT)\ndef delete_user(user_id: int):\n \"\"\"Удалить пользователя\"\"\"\n return None\n\n# HEAD - как GET, но без body\n@app.head(\"/users\")\ndef head_users():\n \"\"\"Проверить, существует ли ресурс\"\"\"\n return {}\n\n# OPTIONS - описать доступные методы\n@app.options(\"/users\")\ndef options_users():\n \"\"\"Какие методы доступны для ресурса\"\"\"\n return {\"methods\": [\"GET\", \"POST\", \"PUT\", \"DELETE\"]}\n```\n\n### HTTP коды ответов\n\n```python\n# 2xx - Успех\n200 OK # Запрос успешен\n201 Created # Ресурс создан\n204 No Content # Успех, но нет контента\n\n# 3xx - Перенаправление\n301 Moved Permanently # Ресурс перемещен навсегда\n304 Not Modified # Используй кэш\n\n# 4xx - Ошибка клиента\n400 Bad Request # Неверный запрос\n401 Unauthorized # Нужна аутентификация\n403 Forbidden # Нет прав доступа\n404 Not Found # Ресурс не найден\n409 Conflict # Конфликт (напр., дублирование)\n\n# 5xx - Ошибка сервера\n500 Internal Error # Ошибка на сервере\n503 Service Unavailable # Сервис недоступен\n```\n\n### Пример полного REST API\n\n```python\nfrom fastapi import FastAPI, HTTPException, status\nfrom typing import List\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nclass UserSchema(BaseModel):\n id: int\n name: str\n email: str\n\nusers = {}\n\n@app.get(\"/users\", response_model=List[UserSchema])\ndef get_users():\n return list(users.values())\n\n@app.post(\"/users\", status_code=status.HTTP_201_CREATED, response_model=UserSchema)\ndef create_user(user: UserSchema):\n if user.id in users:\n raise HTTPException(status_code=409, detail=\"User already exists\")\n users[user.id] = user\n return user\n\n@app.get(\"/users/{user_id}\", response_model=UserSchema)\ndef get_user(user_id: int):\n if user_id not in users:\n raise HTTPException(status_code=404, detail=\"User not found\")\n return users[user_id]\n\n@app.put(\"/users/{user_id}\", response_model=UserSchema)\ndef update_user(user_id: int, user: UserSchema):\n if user_id not in users:\n raise HTTPException(status_code=404, detail=\"User not found\")\n users[user_id] = user\n return user\n\n@app.delete(\"/users/{user_id}\", status_code=status.HTTP_204_NO_CONTENT)\ndef delete_user(user_id: int):\n if user_id not in users:\n raise HTTPException(status_code=404, detail=\"User not found\")\n del users[user_id]\n return None\n```\n\n### Резюме\n\nREST API — это архитектурный стиль, который использует:\n- HTTP методы (GET, POST, PUT, DELETE, PATCH) для операций\n- URI для идентификации ресурсов\n- HTTP коды для статусов\n- Принципы: stateless, cacheable, layered, uniform interface\n\nЭто делает API предсказуемым, масштабируемым и простым для интеграции.","dateCreated":"2026-03-22T20:58:55.695365","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Что такое REST API и его принципы?

2.0 Middle🔥 281 комментариев
#REST API и HTTP#Архитектура и паттерны

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

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

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

Что такое REST API и его принципы

REST (Representational State Transfer) — архитектурный стиль для построения масштабируемых веб-сервисов, которые используют HTTP протокол для операций над ресурсами.

Что такое REST API?

REST API — это интерфейс, который позволяет клиентам взаимодействовать с сервером через HTTP запросы для выполнения CRUD операций (Create, Read, Update, Delete) над ресурсами.

# Пример REST API на FastAPI
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

# In-memory хранилище
users_db = {}

# CREATE
@app.post("/users")
def create_user(user: User):
    users_db[user.id] = user
    return {"message": "User created", "user": user}

# READ
@app.get("/users/{user_id}")
def get_user(user_id: int):
    if user_id not in users_db:
        return {"error": "User not found"}
    return users_db[user_id]

# UPDATE
@app.put("/users/{user_id}")
def update_user(user_id: int, user: User):
    users_db[user_id] = user
    return {"message": "User updated", "user": user}

# DELETE
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    if user_id in users_db:
        del users_db[user_id]
        return {"message": "User deleted"}
    return {"error": "User not found"}

6 основных принципов REST

1. Client-Server архитектура

Клиент и сервер разделены и независимы друг от друга:

# Клиент (JavaScript)
fetch('/api/users/1')
    .then(response => response.json())
    .then(data => console.log(data));

# Сервер (Python)
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "John"}

# Клиент не знает, как сервер хранит данные
# Сервер не зависит от клиента

2. Statelessness (Безсостояние)

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

# Хорошо: Stateless
@app.get("/users/{user_id}")
def get_user(user_id: int, token: str = Header(None)):
    # Проверяем token в каждом запросе
    if not verify_token(token):
        raise HTTPException(status_code=401)
    return {"id": user_id, "name": "John"}

# Плохо: Stateful
sessions = {}

@app.post("/login")
def login(username: str, password: str):
    # Сохраняем состояние сессии на сервере
    session_id = str(uuid.uuid4())
    sessions[session_id] = {"username": username, "logged_in": True}
    return {"session_id": session_id}

@app.get("/profile")
def get_profile(session_id: str):
    # Зависит от состояния, хранящегося на сервере
    if session_id not in sessions:
        raise HTTPException(status_code=401)
    return {"user": sessions[session_id]["username"]}

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

Ответы должны быть явно обозначены как кэшируемые или не кэшируемые:

from fastapi import Response
from datetime import datetime, timedelta

# Кэшируемый ответ
@app.get("/static-data")
def get_static_data():
    return Response(
        content="Static data",
        headers={
            "Cache-Control": "public, max-age=3600",  # Кэш на 1 час
            "ETag": '"123456"',
            "Last-Modified": datetime.now().isoformat()
        }
    )

# Не кэшируемый ответ
@app.get("/dynamic-data")
def get_dynamic_data():
    return Response(
        content="Dynamic data",
        headers={
            "Cache-Control": "no-cache, no-store, must-revalidate",
            "Pragma": "no-cache",
            "Expires": "0"
        }
    )

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

Три компонента:

a) Идентификация ресурсов в запросе

# Правильно: ресурсы идентифицируются URI
GET /api/users/123        # Конкретный пользователь
GET /api/users            # Все пользователи
GET /api/users/123/posts  # Посты пользователя

# Неправильно: действия в URI
GET /api/getUser/123
GET /api/deleteUser/123
GET /api/updateUser/123

b) Манипуляция ресурсов через представления

# Правильно: используем HTTP методы для операций
POST /users              # Создать
GET /users/123           # Прочитать
PUT /users/123           # Полное обновление
PATCH /users/123         # Частичное обновление
DELETE /users/123        # Удалить

# Пример на FastAPI
@app.post("/users")           # Create
def create_user(user: User): ...

@app.get("/users/{id}")       # Read
def read_user(id: int): ...

@app.put("/users/{id}")       # Update (все поля)
def update_user(id: int, user: User): ...

@app.patch("/users/{id}")     # Update (отдельные поля)
def partial_update(id: int, user: dict): ...

@app.delete("/users/{id}")    # Delete
def delete_user(id: int): ...

c) Саморазъясняющиеся сообщения

from fastapi import status, Response

@app.post("/users", status_code=status.HTTP_201_CREATED)
def create_user(user: User):
    # Response явно указывает, что создано новое
    return Response(
        content={"id": 1, "name": "John"},
        status_code=201,
        headers={"Content-Type": "application/json"}
    )

@app.get("/users/{user_id}", response_model=User)
def get_user(user_id: int):
    # Response явно указывает формат
    return {"id": user_id, "name": "John"}

5. Layered System (Многоуровневая архитектура)

Клиент не может сказать, подключен ли он напрямую к конечному серверу:

# API Gateway layer
@app.get("/api/v1/users/{user_id}")
def get_user_v1(user_id: int):
    # Может перенаправлять на разные сервисы
    return requests.get(f"http://user-service:8001/users/{user_id}")

# Балансировка нагрузки
# Client -> Load Balancer -> Server 1, Server 2, Server 3

# Кэширование на промежуточном уровне
@app.get("/api/v1/users/{user_id}")
def get_user(user_id: int):
    # Проверяем кэш
    cached = redis.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    # Если нет в кэше, берём из БД
    user = db.query(User).get(user_id)
    redis.set(f"user:{user_id}", json.dumps(user))
    return user

6. Code on Demand (Опционально)

Сервер может расширять функциональность клиента, отправляя исполняемый код:

# Редко используется, но возможно
@app.get("/api/script.js")
def get_script():
    script = """
    function validateEmail(email) {
        return email.includes('@');
    }
    """
    return Response(content=script, media_type="application/javascript")

# На фронте
# <script src="/api/script.js"></script>

HTTP методы и их использование

from fastapi import FastAPI, status

app = FastAPI()

# GET - безопасен, идемпотентен, кэшируется
@app.get("/users")
def list_users():
    """Получить всех пользователей"""
    return []

# POST - не идемпотентен, создает новые ресурсы
@app.post("/users", status_code=status.HTTP_201_CREATED)
def create_user(user: dict):
    """Создать нового пользователя"""
    return {"id": 1, **user}

# PUT - идемпотентен, заменяет весь ресурс
@app.put("/users/{user_id}")
def replace_user(user_id: int, user: dict):
    """Полностью заменить пользователя"""
    return {"id": user_id, **user}

# PATCH - не идемпотентен, обновляет части ресурса
@app.patch("/users/{user_id}")
def update_user(user_id: int, updates: dict):
    """Обновить часть пользователя"""
    return {"id": user_id, "name": "Updated"}

# DELETE - идемпотентен
@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int):
    """Удалить пользователя"""
    return None

# HEAD - как GET, но без body
@app.head("/users")
def head_users():
    """Проверить, существует ли ресурс"""
    return {}

# OPTIONS - описать доступные методы
@app.options("/users")
def options_users():
    """Какие методы доступны для ресурса"""
    return {"methods": ["GET", "POST", "PUT", "DELETE"]}

HTTP коды ответов

# 2xx - Успех
200 OK                  # Запрос успешен
201 Created            # Ресурс создан
204 No Content         # Успех, но нет контента

# 3xx - Перенаправление
301 Moved Permanently  # Ресурс перемещен навсегда
304 Not Modified       # Используй кэш

# 4xx - Ошибка клиента
400 Bad Request        # Неверный запрос
401 Unauthorized       # Нужна аутентификация
403 Forbidden          # Нет прав доступа
404 Not Found          # Ресурс не найден
409 Conflict           # Конфликт (напр., дублирование)

# 5xx - Ошибка сервера
500 Internal Error     # Ошибка на сервере
503 Service Unavailable # Сервис недоступен

Пример полного REST API

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

app = FastAPI()

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

users = {}

@app.get("/users", response_model=List[UserSchema])
def get_users():
    return list(users.values())

@app.post("/users", status_code=status.HTTP_201_CREATED, response_model=UserSchema)
def create_user(user: UserSchema):
    if user.id in users:
        raise HTTPException(status_code=409, detail="User already exists")
    users[user.id] = user
    return user

@app.get("/users/{user_id}", response_model=UserSchema)
def get_user(user_id: int):
    if user_id not in users:
        raise HTTPException(status_code=404, detail="User not found")
    return users[user_id]

@app.put("/users/{user_id}", response_model=UserSchema)
def update_user(user_id: int, user: UserSchema):
    if user_id not in users:
        raise HTTPException(status_code=404, detail="User not found")
    users[user_id] = user
    return user

@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int):
    if user_id not in users:
        raise HTTPException(status_code=404, detail="User not found")
    del users[user_id]
    return None

Резюме

REST API — это архитектурный стиль, который использует:

  • HTTP методы (GET, POST, PUT, DELETE, PATCH) для операций
  • URI для идентификации ресурсов
  • HTTP коды для статусов
  • Принципы: stateless, cacheable, layered, uniform interface

Это делает API предсказуемым, масштабируемым и простым для интеграции.