Ir para o conteúdo

Stride

Framework estilo Django para FastAPI. Models, ViewSets, Auth, Admin — baterias incluídas.

Arquitetura

flowchart TB
    subgraph "Client Layer"
        WEB[Web/Mobile]
        CLI[CLI Tools]
    end
    
    subgraph "Stride"
        subgraph "API Layer"
            RT[AutoRouter]
            VS[ViewSets]
            AUTH[Auth/JWT]
        end
        
        subgraph "Business Layer"
            PERM[Permissions]
            VALID[Validators]
            SER[Serializers]
        end
        
        subgraph "Data Layer"
            MOD[Models]
            QS[QuerySets]
            REL[Relations]
        end
        
        subgraph "Infrastructure"
            MW[Middleware]
            MSG[Messaging]
            TASK[Workers]
        end
    end
    
    subgraph "Storage"
        DB[(PostgreSQL)]
        CACHE[(Redis)]
        MQ[Kafka]
    end
    
    WEB --> RT
    CLI --> RT
    RT --> VS --> PERM --> MOD --> DB
    VS --> VALID
    VS --> SER
    MOD --> QS
    MOD --> REL
    MW --> AUTH
    MSG --> MQ
    TASK --> CACHE
    
    style VS fill:#e3f2fd
    style MOD fill:#c8e6c9
    style AUTH fill:#fff3e0

Filosofia Plug-and-Play

Configure no Settings, tudo é auto-configurado:

class AppSettings(Settings):
    # Auth - auto-configurado
    user_model: str = "src.apps.users.models.User"
    
    # Kafka - auto-configurado
    kafka_enabled: bool = True
    
    # Tasks - auto-configurado
    task_enabled: bool = True
    
    # Multi-tenancy - auto-configurado
    tenancy_enabled: bool = True

Zero chamadas explícitas: Você NÃO precisa chamar configure_auth(), configure_kafka(), etc.

Instalação

pipx install stride
stride init my-api && cd my-api
stride run
# → http://localhost:8000/docs

Documentação

Começando

Doc Descrição
Criar uma aplicação Guia completo: config, DB, ViewSet, APIView, serializers, paginação, WebSocket, SSE, validação
Quickstart Primeira API em 5 minutos
Settings Sistema de configuração plug-and-play
Models Modelos de banco de dados
ViewSets Endpoints CRUD

Autenticação

Doc Descrição
Auth Autenticação JWT
Auth Backends Backends customizados
CLI Referência de comandos
Permissions Controle de acesso

Camada de Dados

Doc Descrição
Fields Todos os tipos de campos
Relations Relacionamentos
QuerySets Queries estilo Django
Serializers Schemas de Input/Output
Validators Validação de dados

Infraestrutura

Doc Descrição
Middleware Hooks de request/response
Database Replicas Separação read/write
Soft Delete Deleção lógica
Routing Roteamento de URLs
Dependencies Injeção de dependências
Real-time WebSocket, SSE & Channels

Avançado

Doc Descrição
Messaging Integração Kafka/Redis
Workers Workers em background
Tenancy Multi-tenant
Choices TextChoices/IntegerChoices
Exceptions Tratamento de erros
DateTime Tratamento de timezone
Security Boas práticas de segurança
Storage Armazenamento de arquivos, Signed URLs para buckets privados

Referência

Doc Descrição
Admin Painel administrativo
Migrations Migrations de banco

Estrutura do Projeto

my-api/
├── src/
│   ├── settings.py      # Toda configuração aqui
│   ├── main.py          # Entry point da app
│   └── apps/
│       ├── models.py    # Imports de models (barrel)
│       └── items/
│           ├── models.py
│           ├── views.py
│           └── routes.py
├── migrations/
├── .env
└── pyproject.toml

Exemplo Mínimo

# src/settings.py
from strider.config import Settings, configure

class AppSettings(Settings):
    app_name: str = "Minha API"

settings = configure(settings_class=AppSettings)
# src/apps/items/models.py
from strider import Model, Field
from sqlalchemy.orm import Mapped

class Item(Model):
    __tablename__ = "items"
    id: Mapped[int] = Field.pk()
    name: Mapped[str] = Field.string(max_length=200)
# src/apps/items/views.py
from strider import ModelViewSet
from .models import Item

class ItemViewSet(ModelViewSet):
    model = Item
# src/main.py
from strider import StrideApp, AutoRouter
from src.apps.items.routes import router as items_router

api = AutoRouter(prefix="/api/v1")
api.include_router(items_router)

app = StrideApp(routers=[api])

Exemplo Completo com Auto-Configuração

# src/settings.py
from strider.config import Settings, PydanticField, configure

class AppSettings(Settings):
    # ══════════════════════════════════════════════════════════════════
    # Aplicação
    # ══════════════════════════════════════════════════════════════════
    app_name: str = "Minha API"
    app_version: str = "1.0.0"
    
    # ══════════════════════════════════════════════════════════════════
    # Auth (auto-configurado quando user_model definido)
    # ══════════════════════════════════════════════════════════════════
    user_model: str = "src.apps.users.models.User"
    models_module: str = "src.apps"
    auth_password_hasher: str = "argon2"
    
    # ══════════════════════════════════════════════════════════════════
    # Kafka (auto-configurado quando kafka_enabled=True)
    # ══════════════════════════════════════════════════════════════════
    kafka_enabled: bool = True
    kafka_bootstrap_servers: str = "kafka:9092"
    avro_default_namespace: str = "com.mycompany.events"
    
    # ══════════════════════════════════════════════════════════════════
    # Tasks (auto-configurado quando task_enabled=True)
    # ══════════════════════════════════════════════════════════════════
    task_enabled: bool = True
    task_worker_concurrency: int = 8
    
    # ══════════════════════════════════════════════════════════════════
    # Multi-tenancy
    # ══════════════════════════════════════════════════════════════════
    tenancy_enabled: bool = True
    tenancy_field: str = "workspace_id"
    
    # ══════════════════════════════════════════════════════════════════
    # Middleware
    # ══════════════════════════════════════════════════════════════════
    middleware: list[str] = [
        "timing",
        "request_id",
        "tenant",
        "auth",
        "logging",
    ]
    
    # ══════════════════════════════════════════════════════════════════
    # Admin
    # ══════════════════════════════════════════════════════════════════
    admin_site_title: str = "Minha Empresa"
    admin_primary_color: str = "#10B981"
    
    # ══════════════════════════════════════════════════════════════════
    # Campos customizados
    # ══════════════════════════════════════════════════════════════════
    stripe_api_key: str = PydanticField(default="", description="Stripe API Key")

# Configura TUDO automaticamente
settings = configure(settings_class=AppSettings)

FileField Nativo (Storage com Signed URLs)

FileField estilo Django para upload e acesso a arquivos com signed URLs:

# 1. Configure no .env
# STORAGE_BACKEND=gcs
# STORAGE_GCS_BUCKET_NAME=meu-bucket
# STORAGE_GCS_CREDENTIALS_FILE=config/gcp-sa.json
# STORAGE_GCS_USE_SIGNED_URLS=true

# 2. No model, use AdvancedField.file() - estilo Django
from strider import Model, Field
from strider.fields import AdvancedField

class Course(Model):
    __tablename__ = "courses"
    id: Mapped[int] = Field.pk()
    
    # Coluna do banco (armazena path)
    cover_url: Mapped[str | None] = Field.string(500, nullable=True)
    
    # FileField nativo
    cover = AdvancedField.file("cover_url", upload_to="courses/covers/")

# 3. Use como Django FileField
course.cover.name     # "courses/covers/abc.jpg"
course.cover.url      # "https://...?X-Goog-Signature=..." (signed URL)
course.cover.save("foto.jpg", content, "image/jpeg")  # Upload
course.cover.delete() # Remove do storage

# 4. Em schemas, transforme com get_file_url()
from strider.storage import get_file_url

class CourseResponse(OutputSchema):
    cover_url: str | None = None
    
    @model_validator(mode="after")
    def transform_urls(self):
        if self.cover_url:
            self.cover_url = get_file_url(self.cover_url)
        return self

Ver: Storage para documentação completa.

Comandos Rápidos

stride init my-api          # Criar projeto
stride init my-api --minimal # Projeto mínimo
stride makemigrations       # Gerar migrations
stride migrate              # Aplicar migrations
stride run                  # Iniciar servidor
core createsuperuser      # Criar usuário admin
core kafka worker --all   # Executar workers