DocsAvanzado
Recetas
Tres cosas que casi todas las aplicaciones necesitan, como archivos completos que puedes copiar. Cada bloque de código a continuación con un filename se escribe en un proyecto nuevo y el conjunto de pruebas lo ejercita, por lo que lo que lee es lo que se ejecuta.
Utilizan controladores API simples; las mismas funciones funcionan detrás de una página en cualquier modo.
Iniciar sesión con una sesión
Un visitante publica un nombre y una contraseña, el servidor los recuerda en una cookie firmada y todo lo que aparece en /api/account está cerrado para cualquier otra persona.
Activa las sesiones. Necesitan itsdangerous (uv add itsdangerous):
from nexy.core.models import NexyConfigModel class NexyConfig(NexyConfigModel): useSession = {"secret_key": "change-me-in-production"}Iniciar y cerrar sesión:
from pydantic import BaseModel from nexy.http import HTTPException, Request USERS = {"ada": "lovelace"} class Credentials(BaseModel): name: str password: str async def POST(request: Request, body: Credentials): if USERS.get(body.name) != body.password: raise HTTPException(status_code=401, detail="Wrong name or password") request.session["user"] = body.name return {"user": body.name}from nexy.http import Request async def POST(request: Request): request.session.clear() return {"signed_out": True}Guarde una carpeta completa con un dependencies.py:
from nexy.http import HTTPException, Request def current_user(request: Request) -> str: if not request.session.get("user"): raise HTTPException(status_code=401, detail="Sign in first") return request.session["user"] dependencies = [current_user]from nexy.http import Request async def GET(request: Request): return {"user": request.session["user"]}Una API JSON con creación, lectura y eliminación.
Una tienda en un módulo, una ruta de recogida y una ruta de artículos. Reemplace el diccionario con una base de datos cuando los datos deban sobrevivir a un reinicio.
from pydantic import BaseModel class Note(BaseModel): id: int title: str NOTES: dict[int, Note] = {}from pydantic import BaseModel from src.notes import NOTES, Note class NewNote(BaseModel): title: str async def GET() -> list[Note]: return list(NOTES.values()) async def POST(body: NewNote) -> Note: note = Note(id=max(NOTES, default=0) + 1, title=body.title) NOTES[note.id] = note return notefrom nexy.http import HTTPException from src.notes import NOTES, Note async def GET(id: int) -> Note: if id not in NOTES: raise HTTPException(status_code=404, detail="No such note") return NOTES[id] async def DELETE(id: int) -> dict[str, bool]: if NOTES.pop(id, None) is None: raise HTTPException(status_code=404, detail="No such note") return {"deleted": True}Un cuerpo que no se ajusta a NewNote se rechaza con 422 antes de que se ejecute el código y la anotación de devolución se convierte en la respuesta documentada. Ver validación y errores.
Recibir un archivo
Las cargas necesitan python-multipart (uv add python-multipart). Verifique el tamaño usted mismo y nunca use el nombre del archivo del cliente como ruta:
from pathlib import Path from nexy.http import HTTPException, UploadFile MAX_BYTES = 1_000_000 async def POST(file: UploadFile) -> dict[str, int | str]: data = await file.read() if len(data) > MAX_BYTES: raise HTTPException(status_code=413, detail="File too large") name = Path(file.filename or "upload").name return {"name": name, "size": len(data)}Path(...).name elimina cualquier carpeta que el cliente haya puesto en el nombre, como ../../etc/passwd. Guarde los bytes con un nombre que genere, no con este.
Próximos pasos
- Acciones: funciones de servidor escritas para formularios y botones
- Middleware y seguridad: CORS, hosts, sesiones
- Pruebas: prueba tus propios controladores de la misma manera