coder16
update
57090be
|
Raw
History Blame Contribute Delete
10.1 kB
metadata
title: Directorio Online API
emoji: 📒
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false

Directorio Online — Backend (FastAPI + MongoDB)

API REST genérica y fácil de extender para un directorio de negocios organizado por categorías, con items (menús, servicios o productos), reseñas e imágenes. Construida con FastAPI y MongoDB (driver pymongo con su API asíncrona), autenticación JWT (OAuth2) y validación con Pydantic v2.

Modelo de datos y relaciones

Categoria
│   (puede anidarse a sí misma vía parent_id)
└── Negocio (N)

Negocio
├── Item (N)        (tipo: menu | servicio | producto)
├── Reseña (N)
└── Imagen (N)      (embebida)

Item
└── Imagen (N)      (embebida)

Los identificadores son el ObjectId de MongoDB, expuesto siempre como cadena en el campo id de las respuestas.

Estructura del proyecto

app/
├── core/         Configuración FastAPI: settings, seguridad (JWT),
│                 middlewares (CORS), lifespan y manejadores de excepciones.
├── database/     Conexión y cliente de MongoDB, índices y utilidades.
├── exceptions/   Excepciones propias de la aplicación.
├── models/       Modelos de dominio (lo que se guarda en la BD).
├── schemas/      Esquemas de entrada/salida con validaciones
│                 (contrato entre rutas y servicios).
├── services/     Lógica de negocio (CRUD genérico + reglas por entidad).
├── rutas/        Endpoints de comunicación con los clientes.
└── main.py       Punto de entrada (crea la app).

Cómo extender

Añadir una nueva entidad es directo gracias al BaseService (app/services/base.py), que implementa el CRUD genérico:

  1. Define el modelo en models/ y los esquemas en schemas/.
  2. Crea un servicio que herede de BaseService (fija collection_name).
  3. Añade el router en rutas/ e inclúyelo en rutas/__init__.py.
  4. (Opcional) Declara índices en database/indexes.py.

Requisitos

  • Python 3.11+
  • MongoDB 4.4+ en ejecución (local o remoto)

Instalación

python -m venv .venv
source .venv/bin/activate        # En Windows: .venv\Scripts\activate
pip install -r requirements.txt

Configuración

Copia .env.example a .env y ajusta los valores:

cp .env.example .env

Genera una clave secreta segura para SECRET_KEY:

python -c "import secrets; print(secrets.token_urlsafe(48))"
Variable Descripción Por defecto
APP_NAME Nombre de la aplicación Directorio Online API
APP_VERSION Versión 1.0.0
APP_DESCRIPTION Descripción de la API (ver .env.example)
DEBUG Modo depuración false
API_PREFIX Prefijo de las rutas /api/v1
PORT Puerto de escucha del contenedor 7860
MONGODB_URI URI de conexión a MongoDB mongodb://localhost:27017
MONGODB_DB_NAME Nombre de la base de datos directorio_online
SECRET_KEY Clave para firmar los JWT (obligatoria)
ALGORITHM Algoritmo de firma del JWT HS256
ACCESS_TOKEN_EXPIRE_MINUTES Validez del token de acceso (minutos) 60
CORS_ORIGINS Orígenes permitidos (lista por comas o *) *

Ejecución

uvicorn app.main:app --reload
  • Documentación interactiva (Swagger): http://localhost:8000/docs
  • Documentación alternativa (ReDoc): http://localhost:8000/redoc
  • Comprobación de salud: http://localhost:8000/health

Docker

La aplicación se empaqueta con el Dockerfile incluido. El contenedor escucha en el puerto indicado por la variable PORT (por defecto 7860).

# Construir la imagen
docker build -t directorio-online-backend .

# Ejecutar (las variables se pasan con -e o con --env-file)
docker run --rm -p 7860:7860 \
  -e SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(48))')" \
  -e MONGODB_URI="mongodb+srv://usuario:password@cluster.mongodb.net" \
  -e MONGODB_DB_NAME="directorio_online" \
  directorio-online-backend

La API quedará disponible en http://localhost:7860 (Swagger en /docs).

Despliegue en HuggingFace Spaces (Docker)

El repositorio está listo para desplegarse como un Space de tipo Docker:

  • El README.md incluye las metadatos del Space en su cabecera YAML (sdk: docker, app_port: 7860).
  • El Dockerfile ejecuta el contenedor como el usuario UID 1000 (requisito de HuggingFace) y arranca uvicorn en el puerto 7860.

Pasos:

  1. Crea un Space → SDK: DockerBlank.
  2. Sube este repositorio al Space (o conéctalo a GitHub).
  3. En Settings → Variables and secrets, define las variables del archivo .env.example:
    • Como Secret: SECRET_KEY y MONGODB_URI.
    • Como Variable: el resto (MONGODB_DB_NAME, CORS_ORIGINS, etc.).
  4. El Space construye la imagen y la API queda expuesta en la URL del Space (https://<usuario>-<space>.hf.space), con Swagger en /docs.

MongoDB: HuggingFace no provee base de datos, así que MONGODB_URI debe apuntar a una instancia accesible desde internet (p. ej. MongoDB Atlas). El driver ya incluye dnspython (extra pymongo[srv]) para los URIs mongodb+srv://.

Autenticación

  • La lectura (GET) es pública.
  • La escritura (POST/PUT/DELETE) requiere un token JWT.
# 1) Registrar un usuario
curl -X POST http://localhost:8000/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","email":"admin@correo.com","password":"supersecreta"}'

# 2) Iniciar sesión (formulario OAuth2; "username" admite usuario o correo)
curl -X POST http://localhost:8000/api/v1/auth/login \
  -d "username=admin&password=supersecreta"

# 3) Usar el token en las operaciones de escritura
curl -X POST http://localhost:8000/api/v1/categorias \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"nombre":"Restaurantes"}'

Endpoints principales

Método Ruta Auth Descripción
POST /api/v1/auth/register Registrar usuario
POST /api/v1/auth/login Iniciar sesión (devuelve JWT)
GET /api/v1/auth/me Usuario autenticado
GET /api/v1/categorias Listar categorías
POST /api/v1/categorias Crear categoría
GET /api/v1/categorias/{id} Obtener categoría
PUT /api/v1/categorias/{id} Actualizar categoría
DELETE /api/v1/categorias/{id} Eliminar categoría
GET /api/v1/negocios Listar negocios (filtros)
POST /api/v1/negocios Crear negocio
GET /api/v1/negocios/{id} Obtener negocio
PUT /api/v1/negocios/{id} Actualizar negocio
DELETE /api/v1/negocios/{id} Eliminar negocio (cascada)
GET /api/v1/items Listar items (filtros)
POST /api/v1/items Crear item
GET /api/v1/items/{id} Obtener item
PUT /api/v1/items/{id} Actualizar item
DELETE /api/v1/items/{id} Eliminar item
GET /api/v1/resenas Listar reseñas (filtros)
POST /api/v1/resenas Crear reseña
GET /api/v1/resenas/{id} Obtener reseña
PUT /api/v1/resenas/{id} Actualizar reseña
DELETE /api/v1/resenas/{id} Eliminar reseña

Filtros y paginación

Todos los listados aceptan skip (≥0) y limit (1–100) y devuelven una respuesta paginada { total, skip, limit, items }.

  • GET /negocios?categoria_id=...&activo=true&buscar=pepe
  • GET /items?negocio_id=...&tipo=menu&activo=true
  • GET /resenas?negocio_id=...
  • GET /categorias?parent_id=...

Reglas de negocio

  • Integridad referencial: al crear un negocio se valida que la categoría exista; al crear items y reseñas se valida que el negocio exista.
  • Borrado en cascada: eliminar un negocio elimina también sus items y reseñas.
  • Categorías: no se puede eliminar una categoría que tenga subcategorías o negocios asociados.
  • Slug único: el slug de la categoría es único; se autogenera a partir del nombre si no se proporciona.

Calidad de código

El código sigue PEP 8 (límite de línea de 99 columnas, configurado en setup.cfg). Para verificarlo:

pip install pycodestyle pyflakes
pyflakes app/
pycodestyle app/