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

Что должно входить во фреймворк?

2.0 Middle🔥 181 комментариев
#Python Core

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

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

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

Что должно входить во фреймворк

Это важный вопрос архитектуры. За 10+ лет я видел фреймворки, которые делали слишком много (монолиты) и слишком мало (пусто). Вот мой список обязательных компонентов.

Ядро фреймворка (ОБЯЗАТЕЛЬНО)

1. HTTP Router и Request/Response handling

# Это основа всего
from framework import Framework, Request, Response

app = Framework()

@app.route("/api/users", methods=["GET", "POST"])
def handle_users(request: Request) -> Response:
    if request.method == "GET":
        users = get_users()
        return Response(json=users, status=200)
    else:
        user = create_user(request.json)
        return Response(json=user, status=201)

# Параметры, query строки, все должно работать
@app.route("/api/users/<int:user_id>")
def get_user(request: Request, user_id: int) -> Response:
    user = find_user(user_id)
    if not user:
        return Response(json={"error": "Not found"}, status=404)
    return Response(json=user)

2. Middleware система

# Для логирования, аутентификации, CORS, и т.д.
class AuthMiddleware:
    def __call__(self, request: Request, next):
        token = request.headers.get("Authorization")
        if not token:
            return Response(json={"error": "Unauthorized"}, status=401)
        
        request.user = verify_token(token)
        return next(request)

class LoggingMiddleware:
    def __call__(self, request: Request, next):
        start = time.time()
        response = next(request)
        duration = time.time() - start
        
        logger.info(f"{request.method} {request.path} - {response.status} ({duration:.2f}s)")
        return response

app.use(LoggingMiddleware())
app.use(AuthMiddleware())

3. Обработка ошибок

# Exception handling должен быть встроен
class HTTPException(Exception):
    def __init__(self, status: int, detail: str):
        self.status = status
        self.detail = detail

@app.error_handler(HTTPException)
def handle_http_error(error: HTTPException) -> Response:
    return Response(
        json={"error": error.detail},
        status=error.status
    )

@app.error_handler(ValueError)
def handle_value_error(error: ValueError) -> Response:
    logger.error(f"Validation error: {error}")
    return Response(
        json={"error": "Invalid data"},
        status=400
    )

Важные компоненты (ДОЛЖНЫ БЫТЬ)

4. Типизация и валидация

# Фреймворк должен поддерживать типизацию
from framework import Schema

class UserSchema(Schema):
    id: int
    name: str
    email: str
    age: int

# Автоматическая валидация
@app.route("/api/users", methods=["POST"])
def create_user(request: Request) -> Response:
    # Автоматически парсит и валидирует
    user_data = UserSchema(**request.json)
    user = save_user(user_data)
    return Response(json=user, status=201)

5. Dependency Injection

# DI должен быть встроен
class UserRepository:
    def get(self, user_id: int):
        return db.query(User).get(user_id)

class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo
    
    def find_user(self, user_id: int):
        return self.repo.get(user_id)

# Фреймворк внедряет зависимости автоматически
@app.route("/api/users/<int:user_id>")
def get_user(request: Request, service: UserService, user_id: int):
    user = service.find_user(user_id)
    return Response(json=user)

6. Логирование

# Встроенное логирование на разных уровнях
from framework import logger

@app.route("/api/action")
def action(request: Request):
    logger.debug("Processing action")
    try:
        result = do_something()
        logger.info(f"Action completed: {result}")
        return Response(json=result)
    except Exception as e:
        logger.error(f"Action failed: {e}")
        raise

7. Конфигурация

# Управление конфигурацией (dev/test/prod)
class Config:
    DEBUG = False
    DATABASE_URL = "postgresql://..."
    SECRET_KEY = "secret"

class DevelopmentConfig(Config):
    DEBUG = True
    DATABASE_URL = "sqlite:///dev.db"

app = Framework(config=DevelopmentConfig())

Полезные компоненты (МОЖНО ДОБАВИТЬ)

8. CORS и безопасность

class CORSMiddleware:
    def __call__(self, request: Request, next):
        response = next(request)
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
        return response

app.use(CORSMiddleware())

9. Кэширование

class Cache:
    def get(self, key: str):
        pass
    
    def set(self, key: str, value, ttl: int):
        pass
    
    def delete(self, key: str):
        pass

# Использование
from framework import cache

@app.route("/api/expensive")
def expensive_operation(request: Request):
    cached = cache.get("expensive_result")
    if cached:
        return Response(json=cached)
    
    result = compute_expensive()
    cache.set("expensive_result", result, ttl=3600)
    return Response(json=result)

10. Pagination и filtering

class Paginator:
    def __init__(self, page: int = 1, per_page: int = 20):
        self.page = page
        self.per_page = per_page
    
    def paginate(self, query):
        offset = (self.page - 1) * self.per_page
        return query.limit(self.per_page).offset(offset)

@app.route("/api/items")
def list_items(request: Request):
    page = request.query.get("page", 1, type=int)
    per_page = request.query.get("per_page", 20, type=int)
    
    paginator = Paginator(page, per_page)
    items = paginator.paginate(db.query(Item))
    
    return Response(json=items)

Чего НЕ должно быть во фреймворке

❌ ORM (слишком специфично)

# Фреймворк не должен навязывать ORM
# SQLAlchemy, Tortoise, Peewee — выбор пользователя
# Фреймворк просто предоставляет интеграцию

❌ WebSocket (можно добавить, но опционально)

# Не все приложения нужны WebSockets
# Должны быть добавлены как опция, не обязательно

❌ GraphQL (слишком специфично)

# GraphQL — выбор архитектуры, не фреймворка
# REST/GraphQL независимы от фреймворка

❌ Встроенная база данных (слишком специфично)

# Пусть пользователь выбирает PostgreSQL, MongoDB, Redis
# Фреймворк просто предоставляет адаптеры

Архитектура фреймворка

# Мой идеальный фреймворк (минималистичный)

from framework import Framework, Request, Response, Middleware
from framework.di import Container
from framework.log import Logger
from framework.config import Config

class MyFramework(Framework):
    def __init__(self, config: Config):
        self.config = config
        self.logger = Logger(config.log_level)
        self.container = Container()  # DI
        self.middleware = []  # Middleware chain
        self.routes = {}  # Route registry
    
    def use(self, middleware: Middleware) -> None:
        """Register middleware"""
        self.middleware.append(middleware)
    
    def route(self, path: str, methods: list = None) -> callable:
        """Register route"""
        def decorator(handler):
            self.routes[path] = (methods or ["GET"], handler)
            return handler
        return decorator
    
    def handle(self, request: Request) -> Response:
        """Main request handling"""
        # Apply middleware
        for mw in self.middleware:
            request = mw.before(request)
        
        # Route to handler
        handler = self.find_handler(request.path, request.method)
        response = handler(request)
        
        # Apply response middleware
        for mw in reversed(self.middleware):
            response = mw.after(response)
        
        return response

Практический пример

# Минимальный фреймворк, готовый к production

app = Framework()

class Database:
    def get_user(self, user_id: int):
        # Реальный запрос
        pass

app.container.register(Database, singleton=True)

@app.route("/api/users/<int:user_id>")
def get_user(request: Request, db: Database, user_id: int):
    user = db.get_user(user_id)
    return Response(json=user, status=200 if user else 404)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=True)

Мой вывод

Хороший фреймворк должен быть:

  1. Минималистичным — только необходимое
  2. Расширяемым — легко добавлять компоненты
  3. Независимым — не навязывает конкретные технологии (ORM, БД)
  4. Type-safe — поддерживает типизацию
  5. Хорошо документированным — примеры и лучшие практики

Примеры хороших фреймворков:

  • FastAPI — минимален, но мощный
  • Flask — простой и расширяемый
  • Django — полнофункциональный (может быть избыточным)
  • Starlette — низкоуровневый, очень контролируемый