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

Когда используется POST HTTP запрос?

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

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

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

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

Когда используется POST HTTP запрос

POST — это один из основных HTTP методов, используемый для создания нового ресурса на сервере или отправки данных для обработки. POST является безопасным и непредсказуемым методом, в отличие от GET.

Основное назначение POST

POST используется для отправки данных в теле запроса и создания нового ресурса на сервере. При успешном создании сервер обычно возвращает статус 201 (Created) с данными созданного ресурса.

Типичные случаи использования

1. Создание нового пользователя

# Запрос
POST /api/v1/users
Host: api.example.com
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123",
  "name": "John Doe"
}

# Ответ (201 Created)
{
  "id": 123,
  "email": "user@example.com",
  "name": "John Doe",
  "created_at": "2024-01-15T10:30:00Z"
}

2. Создание комментария к посту

POST /api/v1/posts/42/comments
Content-Type: application/json

{
  "text": "Great article!",
  "user_id": 123
}

3. Отправка формы (login, registration)

POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123"
}

# Ответ
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "bearer",
  "expires_in": 3600
}

Реализация POST в FastAPI

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
from sqlalchemy.orm import Session
from starlette.responses import JSONResponse

app = FastAPI()

class UserCreate(BaseModel):
    email: EmailStr
    password: str
    name: str

class UserResponse(BaseModel):
    id: int
    email: str
    name: str
    created_at: datetime

# Создание пользователя
@app.post("/api/v1/users", response_model=UserResponse, status_code=201)
async def create_user(user_data: UserCreate, db: Session = Depends(get_db)):
    # Проверить, не существует ли уже
    existing_user = db.query(User).filter(User.email == user_data.email).first()
    if existing_user:
        raise HTTPException(status_code=409, detail="User already exists")
    
    # Создать новый объект
    new_user = User(
        email=user_data.email,
        password=hash_password(user_data.password),
        name=user_data.name,
        created_at=datetime.utcnow()
    )
    
    # Сохранить в БД
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    
    return new_user

# Создание комментария (вложенный ресурс)
@app.post("/api/v1/posts/{post_id}/comments", status_code=201)
async def create_comment(
    post_id: int,
    comment_data: CommentCreate,
    db: Session = Depends(get_db)
):
    # Проверить существование поста
    post = db.query(Post).filter(Post.id == post_id).first()
    if not post:
        raise HTTPException(status_code=404, detail="Post not found")
    
    # Создать комментарий
    comment = Comment(
        post_id=post_id,
        text=comment_data.text,
        user_id=comment_data.user_id,
        created_at=datetime.utcnow()
    )
    
    db.add(comment)
    db.commit()
    db.refresh(comment)
    
    return comment

Реализация POST в Django REST Framework

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_201_CREATED

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
    def create(self, request, *args, **kwargs):
        # DRF автоматически вызывает validate() и save()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=HTTP_201_CREATED, headers=headers)
    
    def perform_create(self, serializer):
        # Кастомная логика перед сохранением
        serializer.save(created_by=self.request.user)
    
    # Кастомное POST действие
    @action(detail=False, methods=[post])
    def bulk_create(self, request):
        users_data = request.data  # Список объектов
        users = [User(**user) for user in users_data]
        User.objects.bulk_create(users)
        return Response(
            {"created": len(users)},
            status=HTTP_201_CREATED
        )

HTTP статус-коды для POST

2xx Success:

  • 201 Created — ресурс успешно создан (рекомендуется)
  • 200 OK — операция выполнена, но ресурс не создан
  • 202 Accepted — запрос принят, но обрабатывается асинхронно

4xx Client Error:

  • 400 Bad Request — неверный формат данных
  • 401 Unauthorized — нет авторизации
  • 403 Forbidden — нет прав на создание
  • 409 Conflict — конфликт (например, дублирование уникального поля)
  • 422 Unprocessable Entity — ошибка валидации данных

5xx Server Error:

  • 500 Internal Server Error — ошибка при обработке

Характеристики POST

1. НЕ идемпотентен

Различие POST от PUT/DELETE:

# Первый POST — создан пользователь с ID 123
POST /api/v1/users
{
  "email": "user@example.com",
  "name": "John"
}
→ 201 Created: {"id": 123, ...}

# Второй POST — создан НОВЫЙ пользователь с ID 124
POST /api/v1/users
{
  "email": "user@example.com",
  "name": "John"
}
→ 201 Created: {"id": 124, ...}
# ❌ Это может быть проблемой!

Поэтому важна проверка на дубликаты.

2. Содержит тело запроса

Все данные передаются в теле, а не в URL:

# ✅ Правильно
POST /api/v1/users
Content-Type: application/json
{"email": "user@example.com", "name": "John"}

# ❌ Неправильно
POST /api/v1/users?email=user@example.com&name=John

3. Не кешируется браузером по умолчанию

В отличие от GET, результаты POST не кешируются.

POST для других операций (не только создание)

HOT используется для других операций, когда GET/PUT/DELETE не подходят:

1. Поиск с сложными фильтрами

# POST для сложного поиска (когда много параметров)
POST /api/v1/products/search
{
  "category": "electronics",
  "price_min": 100,
  "price_max": 5000,
  "brands": ["Samsung", "LG"],
  "in_stock": true
}

2. Действия над ресурсами

# Отправить письмо
POST /api/v1/emails/send
{
  "to": "user@example.com",
  "subject": "Verify your email",
  "template": "verification"
}

# Опубликовать пост
POST /api/v1/posts/123/publish

# Отправить приглашение
POST /api/v1/teams/456/invite
{
  "email": "newuser@example.com"
}

3. Upload файлов

from fastapi import UploadFile, File

@app.post("/api/v1/files/upload")
async def upload_file(file: UploadFile = File(...)):
    # Сохранить файл
    with open(f"uploads/{file.filename}", "wb") as buffer:
        buffer.write(await file.read())
    
    return {"filename": file.filename, "size": len(await file.read())}

# multipart/form-data запрос
POST /api/v1/files/upload
Content-Type: multipart/form-data

[Binary file data]

Идемпотентность и дублирование

Поскольку POST не идемпотентен, важно предотвращать дублирование:

from uuid import uuid4

@app.post("/api/v1/users")
async def create_user(
    user_data: UserCreate,
    idempotency_key: str = Header(default=None),
    db: Session = Depends(get_db)
):
    # Проверить, есть ли уже запрос с этим ключом
    existing = db.query(RequestLog).filter(
        RequestLog.idempotency_key == idempotency_key
    ).first()
    
    if existing:
        return existing.response  # Вернуть сохранённый ответ
    
    # Создать пользователя
    new_user = User(**user_data.dict())
    db.add(new_user)
    db.commit()
    
    # Сохранить логи запроса для идемпотентности
    log = RequestLog(
        idempotency_key=idempotency_key,
        response=new_user.dict()
    )
    db.add(log)
    db.commit()
    
    return new_user

Вывод

POST используется для:

  • Создания новых ресурсов (основное назначение) → 201 Created
  • Отправки данных для обработки (поиск, операции)
  • Upload файлов в multipart/form-data

Ключевые отличия:

  • Не идемпотентен — каждый POST может создать новый ресурс
  • Содержит тело — данные передаются в body, не в URL
  • Не кешируется — результаты не сохраняются браузером
  • 201 Created — рекомендуемый статус при успешном создании

Важно помнить о проверке дубликатов и использовании Idempotency-Key для безопасных повторов.

Когда используется POST HTTP запрос? | PrepBro