Статус-коды HTTP: 2xx, 3xx, 4xx, 5xx

Статус-коды HTTP: 2xx, 3xx, 4xx, 5xx REST API

Привет! Статус-коды HTTP — это способ для сервера сказать клиенту, что произошло с его запросом. Каждый код имеет своё значение и помогает клиенту понять, как обрабатывать ответ.

В этой статье мы разберём:

  • Успешные (2xx)
  • Перенаправления (3xx)
  • Ошибки клиента (4xx)
  • Ошибки сервера (5xx)
  • Примеры использования в FastAPI

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Базовое понимание HTTP и REST API
  • Установленный FastAPI

Совет: Правильное использование статус-кодов делает API понятным и удобным.

Основная часть

Общая классификация

ДиапазонНазначение
1xxИнформационные
2xxУспех
3xxПеренаправление
4xxОшибка клиента
5xxОшибка сервера

Успешные коды (2xx)

КодНазваниеЗначение
200OKУспешный запрос
201CreatedРесурс создан
202AcceptedЗапрос принят в обработку
204No ContentУспех, но тело пустое

Примеры в FastAPI:

from fastapi import FastAPI, status
from fastapi.responses import JSONResponse

app = FastAPI()

# 200 OK
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "Анна"}  # По умолчанию 200

# 201 Created
@app.post("/users/")
def create_user(name: str):
    return JSONResponse(
        status_code=status.HTTP_201_CREATED,
        content={"message": "Пользователь создан"}
    )

# 204 No Content
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    # Удаляем пользователя
    return Response(status_code=status.HTTP_204_NO_CONTENT)

Коды перенаправления (3xx)

КодНазваниеЗначение
301Moved PermanentlyРесурс перемещён навсегда
302FoundВременное перенаправление
304Not ModifiedРесурс не изменился

Пример в FastAPI:

from fastapi.responses import RedirectResponse

@app.get("/old-page")
def old_page():
    return RedirectResponse(url="/new-page", status_code=301)

Ошибки клиента (4xx)

КодНазваниеЗначение
400Bad RequestНеверный запрос
401UnauthorizedТребуется авторизация
403ForbiddenДоступ запрещён
404Not FoundРесурс не найден
405Method Not AllowedМетод не поддерживается
409ConflictКонфликт данных
422Unprocessable EntityОшибка валидации

Примеры в FastAPI:

from fastapi import FastAPI, HTTPException

app = FastAPI()

# 404 Not Found
@app.get("/users/{user_id}")
def get_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="Пользователь не найден")
    return users_db[user_id]

# 400 Bad Request
@app.post("/users/")
def create_user(name: str, age: int):
    if age < 0:
        raise HTTPException(status_code=400, detail="Возраст не может быть отрицательным")
    return {"message": "Пользователь создан"}

# 401 Unauthorized
@app.get("/admin/")
def admin_only(token: str):
    if token != "secret":
        raise HTTPException(status_code=401, detail="Неверный токен")
    return {"message": "Добро пожаловать, администратор!"}

# 403 Forbidden
@app.get("/admin/users/")
def admin_users(user_id: int):
    if user_id != 1:  # Только пользователь с id=1 может просматривать
        raise HTTPException(status_code=403, detail="Недостаточно прав")
    return {"users": users_db}

# 409 Conflict
@app.post("/users/")
def create_user(name: str):
    if any(user["name"] == name for user in users_db.values()):
        raise HTTPException(status_code=409, detail="Пользователь с таким именем уже существует")
    return {"message": "Пользователь создан"}

# 422 Unprocessable Entity (автоматически от FastAPI)
# Возникает при ошибках валидации Pydantic

Ошибки сервера (5xx)

КодНазваниеЗначение
500Internal Server ErrorВнутренняя ошибка сервера
502Bad GatewayОшибка шлюза
503Service UnavailableСервис недоступен

Пример в FastAPI:

@app.get("/calculate/{value}")
def calculate(value: int):
    try:
        result = 100 / value
        return {"result": result}
    except ZeroDivisionError:
        raise HTTPException(status_code=500, detail="Ошибка вычисления")

Использование status в FastAPI

from fastapi import FastAPI, status
from fastapi.responses import JSONResponse

app = FastAPI()

@app.post("/users/")
def create_user(name: str):
    return JSONResponse(
        status_code=status.HTTP_201_CREATED,
        content={"message": "Пользователь создан", "user": {"name": name}}
    )

Совет: Используй status.HTTP_XXX вместо чисел — это делает код читаемее.

Полный пример

from fastapi import FastAPI, status, HTTPException
from fastapi.responses import JSONResponse

app = FastAPI()

users_db = {}

@app.get("/users/")
def get_users():
    return {"users": list(users_db.values())}

@app.get("/users/{user_id}")
def get_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="Пользователь не найден")
    return users_db[user_id]

@app.post("/users/")
def create_user(name: str, age: int):
    if age < 0:
        raise HTTPException(status_code=400, detail="Возраст не может быть отрицательным")
    user_id = len(users_db) + 1
    users_db[user_id] = {"id": user_id, "name": name, "age": age}
    return JSONResponse(
        status_code=status.HTTP_201_CREATED,
        content={"message": "Пользователь создан", "user": users_db[user_id]}
    )

@app.put("/users/{user_id}")
def update_user(user_id: int, name: str):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="Пользователь не найден")
    users_db[user_id]["name"] = name
    return {"message": "Пользователь обновлён"}

@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="Пользователь не найден")
    del users_db[user_id]
    return JSONResponse(
        status_code=status.HTTP_204_NO_CONTENT,
        content=None
    )

@app.get("/admin/")
def admin(token: str):
    if token != "secret":
        raise HTTPException(status_code=401, detail="Неверный токен")
    return {"message": "Добро пожаловать, администратор!"}

Задачи для закрепления

Задача 1. Создай эндпоинт, возвращающий 201 при создании ресурса.

Задача 2. Создай эндпоинт, возвращающий 404 при отсутствии ресурса.

Задача 3. Создай эндпоинт, возвращающий 400 при неверных данных.

Задача 4. Создай эндпоинт, возвращающий 204 при удалении.

Задача 5. Создай эндпоинт, возвращающий 401 при неверном токене.

Задача 6. Создай эндпоинт, возвращающий 409 при конфликте данных.

Ответы:

Задача 1.

@app.post("/items/")
def create_item(name: str):
    return JSONResponse(status_code=201, content={"message": "Создано"})

Задача 2.

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in items_db:
        raise HTTPException(status_code=404, detail="Не найдено")
    return items_db[item_id]

Задача 3.

@app.post("/items/")
def create_item(name: str, price: float):
    if price < 0:
        raise HTTPException(status_code=400, detail="Цена не может быть отрицательной")
    return {"message": "Создано"}

Задача 4.

@app.delete("/items/{item_id}")
def delete_item(item_id: int):
    return JSONResponse(status_code=204, content=None)

Задача 5.

@app.get("/admin/")
def admin(token: str):
    if token != "secret":
        raise HTTPException(status_code=401, detail="Неверный токен")
    return {"message": "Добро пожаловать"}

Задача 6.

@app.post("/items/")
def create_item(name: str):
    if any(item["name"] == name for item in items_db.values()):
        raise HTTPException(status_code=409, detail="Товар с таким именем уже существует")
    return {"message": "Создано"}

Нюансы и подводные камни

  • 2xx — успех. 200 OK, 201 Created, 204 No Content.
  • 3xx — редиректы. 301 Moved Permanently, 302 Found.
  • 4xx — ошибки клиента. 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Entity.
  • 5xx — ошибки сервера. 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable.
  • Используй правильные статус-коды для каждого случая.
  • 401 и 403 — разные вещи. 401 — не авторизован, 403 — нет прав.
  • 422 — ошибка валидации данных.

Частые ошибки и как их избежать

Ошибка 1: Возврат 200 при создании ресурса

Используй 201 Created для POST.

Ошибка 2: Путаница между 401 и 403

401 — не авторизован. 403 — доступ запрещён.

Ошибка 3: Возврат 500 для ошибок клиента

Используй 4xx для ошибок клиента.

Шпаргалка

КодНазваниеИспользование
200OKУспешный GET/PUT
201CreatedУспешный POST
204No ContentУспешный DELETE
301Moved PermanentlyПеренаправление
400Bad RequestНеверные данные
401UnauthorizedНет авторизации
403ForbiddenДоступ запрещён
404Not FoundРесурс не найден
409ConflictКонфликт данных
422UnprocessableОшибка валидации
500Internal ServerОшибка сервера

Заключение

Сегодня мы:

  • Изучили статус-коды HTTP
  • Разобрали 2xx, 3xx, 4xx, 5xx
  • Примеры в FastAPI
  • Практические рекомендации

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×