Python15 de diciembre de 2025 20 vistas

Cómo implementar una API Flask o FastAPI en OuiPanel

Cómo implementar una API Flask o FastAPI en OuiPanel

Cómo implementar una API Flask o FastAPI en OuiPanel

Tiempo estimado: 15 minutos
Dificultad: Intermedia ⭐⭐
Tipo de servidor: Python


📋 Introducción

Esta guía explica cómo alojar una API REST desarrollada con Flask o FastAPI en OuiPanel. Su API estará disponible las 24 horas del día, los 7 días de la semana, con la posibilidad de agregar un nombre de dominio personalizado y HTTPS.

Flask vs FastAPI

Criterio Flask FastAPI
Dificultad Principiante Intermedio
Instalación Sencilla (sin compilación) Pesada (compilación Rust)
Requisito de espacio en disco ~100 MB ~5 GB mínimo
Rendimiento Bueno Excelente (async)
Documentación automática No (extensión) Sí (Swagger/OpenAPI)
Validación de datos Manual Automática (Pydantic)
Ideal para APIs simples, servidores pequeños APIs modernas, servidores grandes

💡 Recomendación: Si tiene un servidor con poco almacenamiento (< 5 GB), utilice Flask.

Lo que necesitas

Requisito Descripción
📁 Tu código de API Archivos Python (app.py, main.py...)
🐍 Un servidor Python Ordenado en OuiHeberg
🌐 Un nombre de dominio (Opcional) Para acceder mediante una URL personalizada

💡 ¿Todavía no tienes un servidor Python?
Ordénalo en: https://www.ouiheberg.com/fr/hebergement-python


📁 Paso 1: Preparar los Archivos de la API

Structura de archivos

Tu API debe tener esta estructura:

📁 MiAPI/
├── 📄 app.py             ← Archivo principal (o main.py)
├── 📄 requirements.txt   ← Dependencias Python
├── 📄 .env               ← Variables de entorno (creado en el servidor)
└── 📁 routes/            ← (Opcional) Carpeta de rutas

🌶️ Opción A: API con Flask

Archivo requirements.txt (Flask)

flask==2.3.3
python-dotenv==1.0.0
werkzeug==2.3.7
Paquete Descripción
flask Framework web minimalista
python-dotenv Cargar variables desde .env
werkzeug Utilidades WSGI (incluido con Flask)

⚠️ Importante: Utilice estas versiones exactas para evitar problemas de compatibilidad.


Archivo principal (app.py) - Flask

import os
from dotenv import load_dotenv

# Cargar variables de entorno desde .env
load_dotenv()

from flask import Flask, jsonify, request

# Crear la aplicación Flask
app = Flask(__name__)

# ============================================
# RUTAS DE LA API
# ============================================

# Ruta principal
@app.route('/')
def home():
    return jsonify({
        'status': 'online',
        'message': '¡Bienvenido a mi API Flask!',
        'version': '1.0.0'
    })

# Ruta de salud (health check)
@app.route('/health')
def health():
    return jsonify({
        'status': 'saludable',
        'servicio': 'Mi API Flask'
    })

# Ejemplo de datos (simulando una base de datos)
items = [
    {'id': 1, 'name': 'Item 1', 'price': 10.99},
    {'id': 2, 'name': 'Item 2', 'price': 24.99},
    {'id': 3, 'name': 'Item 3', 'price': 5.49}
]

# GET todos los elementos
@app.route('/api/items', methods=['GET'])
def get_items():
    return jsonify({
        'success': True,
        'data': items,
        'count': len(items)
    })

# GET un elemento por ID
@app.route('/api/items/<int:item_id>', methods=['GET'])
def get_item(item_id):
    for item in items:
        if item['id'] == item_id:
            return jsonify({
                'success': True,
                'data': item
            })
    return jsonify({
        'success': False,
        'error': 'Elemento no encontrado'
    }), 404

# POST crear un elemento
@app.route('/api/items', methods=['POST'])
def create_item():
    data = request.get_json()
    
    if not data or 'name' not in data:
        return jsonify({
            'success': False,
            'error': 'El campo "name" es obligatorio'
        }), 400
    
    new_id = max(item['id'] for item in items) + 1 if items else 1
    new_item = {
        'id': new_id,
        'name': data['name'],
        'price': data.get('price', 0)
    }
    items.append(new_item)
    
    return jsonify({
        'success': True,
        'message': 'Elemento creado exitosamente',
        'data': new_item
    }), 201

# PUT modificar un elemento
@app.route('/api/items/<int:item_id>', methods=['PUT'])
def update_item(item_id):
    data = request.get_json()
    
    for item in items:
        if item['id'] == item_id:
            item['name'] = data.get('name', item['name'])
            item['price'] = data.get('price', item['price'])
            return jsonify({
                'success': True,
                'message': 'Elemento modificado exitosamente',
                'data': item
            })
    
    return jsonify({
        'success': False,
        'error': 'Elemento no encontrado'
    }), 404

# DELETE eliminar un elemento
@app.route('/api/items/<int:item_id>', methods=['DELETE'])
def delete_item(item_id):
    for index, item in enumerate(items):
        if item['id'] == item_id:
            items.pop(index)
            return jsonify({
                'success': True,
                'message': f'Elemento {item_id} eliminado exitosamente'
            })
    
    return jsonify({
        'success': False,
        'error': 'Elemento no encontrado'
    }), 404

# ============================================
# GESTIÓN DE ERRORES
# ============================================

@app.errorhandler(404)
def not_found(error):
    return jsonify({
        'success': False,
        'error': 'Recurso no encontrado'
    }), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({
        'success': False,
        'error': 'Error interno del servidor'
    }), 500

# ============================================
# INICIO DEL SERVIDOR
# ============================================

if __name__ == '__main__':
    # Puerto: usar SERVER_PORT (OuiPanel) o 5000 por defecto
    port = int(os.getenv('SERVER_PORT', 5000))
    
    # IMPORTANTE: Escuchar en 0.0.0.0 para OuiPanel
    app.run(host='0.0.0.0', port=port)

⚠️ IMPORTANTE: La API debe escuchar en 0.0.0.0 y no en localhost o 127.0.0.1 para ser accesible desde el exterior.


⚡ Opción B: API con FastAPI

⚠️ Atención: FastAPI requiere pydantic que debe ser compilado. Esto requiere mucho espacio en disco (varios GB) durante la instalación. Si obtiene un error No space left on device, use Flask en su lugar o aumente el almacenamiento de su servidor.

Archivo requirements.txt (FastAPI)

fastapi==0.104.1
uvicorn==0.24.0
python-dotenv==1.0.0
Paquete Descripción
fastapi Framework web moderno y rápido
uvicorn Servidor ASGI para FastAPI
python-dotenv Cargar variables desde .env

💡 Recomendación de almacenamiento: Reserve al menos 5 GB de almacenamiento libre para la instalación de FastAPI.


Archivo principal (app.py) - FastAPI

import os
from dotenv import load_dotenv

# Cargar variables de entorno desde .env
load_dotenv()

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, List

# Crear la aplicación FastAPI
app = FastAPI(
    title="Mi API FastAPI",
    description="Una API REST moderna con FastAPI",
    version="1.0.0",
    docs_url="/docs",      # Documentación Swagger
    redoc_url="/redoc"     # Documentación ReDoc
)

# ============================================
# MODELOS PYDANTIC (validación de datos)
# ============================================

class ItemCreate(BaseModel):
    name: str
    price: float = 0
    description: Optional[str] = None

class Item(BaseModel):
    id: int
    name: str
    price: float
    description: Optional[str] = None

# ============================================
# DATOS DE EJEMPLO (simulando una base de datos)
# ============================================

items_db = [
    {"id": 1, "name": "Item 1", "price": 10.99, "description": "Primer item"},
    {"id": 2, "name": "Item 2", "price": 24.99, "description": "Segundo item"},
    {"id": 3, "name": "Item 3", "price": 5.49, "description": "Tercer item"},
]

# ============================================
# RUTAS DE LA API
# ============================================

# Ruta principal
@app.get("/", tags=["General"])
async def home():
    return {
        "status": "online",
        "message": "¡Bienvenido a mi API FastAPI!",
        "version": "1.0.0",
        "docs": "/docs"
    }

# Ruta de salud (health check)
@app.get("/health", tags=["General"])
async def health():
    return {
        "status": "saludable",
        "service": "Mi API FastAPI"
    }

# GET todos los elementos
@app.get("/api/items", tags=["Items"])
async def get_items():
    return {
        "success": True,
        "data": items_db,
        "count": len(items_db)
    }

# GET un elemento por ID
@app.get("/api/items/{item_id}", tags=["Items"])
async def get_item(item_id: int):
    for item in items_db:
        if item["id"] == item_id:
            return {"success": True, "data": item}
    raise HTTPException(status_code=404, detail="Elemento no encontrado")

# POST crear un elemento
@app.post("/api/items", status_code=201, tags=["Items"])
async def create_item(item: ItemCreate):
    new_id = max(i["id"] for i in items_db) + 1 if items_db else 1
    new_item = {
        "id": new_id,
        "name": item.name,
        "price": item.price,
        "description": item.description
    }
    items_db.append(new_item)
    return {
        "success": True,
        "message": "Elemento creado exitosamente",
        "data": new_item
    }

# PUT modificar un elemento
@app.put("/api/items/{item_id}", tags=["Items"])
async def update_item(item_id: int, item: ItemCreate):
    for index, existing_item in enumerate(items_db):
        if existing_item["id"] == item_id:
            updated_item = {
                "id": item_id,
                "name": item.name,
                "price": item.price,
                "description": item.description
            }
            items_db[index] = updated_item
            return {
                "success": True,
                "message": "Elemento modificado exitosamente",
                "data": updated_item
            }
    raise HTTPException(status_code=404, detail="Elemento no encontrado")

# DELETE eliminar un elemento
@app.delete("/api/items/{item_id}", tags=["Items"])
async def delete_item(item_id: int):
    for index, item in enumerate(items_db):
        if item["id"] == item_id:
            items_db.pop(index)
            return {"success": True, "message": f"Elemento {item_id} eliminado"}
    raise HTTPException(status_code=404, detail="Elemento no encontrado")

# ============================================
# INICIO DEL SERVIDOR
# ============================================

if __name__ == "__main__":
    import uvicorn
    
    # Puerto: use SERVER_PORT (OuiPanel) or 8000 por defecto
    port = int(os.getenv('SERVER_PORT', 8000))
    
    # IMPORTANTE: Escuchar en 0.0.0.0 para OuiPanel
    uvicorn.run(app, host="0.0.0.0", port=port)

💡 Bono FastAPI: ¡La documentación interactiva se genera automáticamente!

  • Swagger UI: http://your-ip:port/docs
  • ReDoc: http://your-ip:port/redoc

📤 Paso 2: Subir los Archivos a OuiPanel

Mediante el Administrador de Archivos

  1. Inicie sesión en OuiPanel
  2. Seleccione su servidor Python
  3. En el menú lateral, haga clic en Administrador de archivos

Imagen

  1. Elimine los archivos predeterminados (si los hay)
  2. Haga clic en Subir (Upload)
  3. Suba sus archivos:
    • app.py (o main.py)
    • requirements.txt
    • Sus carpetas (routes/, models/...) si es necesario

Imagen

⚠️ No subir: El archivo .env se creará directamente en el servidor (más seguro).


Mediante SFTP (Recomendado para varios archivos)

  1. Inicie sesión en SFTP con FileZilla
  2. Arrastre y suelte todo el contenido de su carpeta API
  3. Verifique que todos los archivos se hayan subido correctamente

📖 Consulte la guía "Acceso SFTP con FileZilla" para obtener instrucciones detalladas.


🔑 Paso 3: Crear el Archivo .env

Crear el archivo .env

  1. En el Administrador de archivos, haga clic en Nuevo archivo
  2. Nómbrelo .env (con el punto delante)
  3. Agregue sus variables:
# Configuración de la API
DEBUG=false
PORT=8000

# Base de datos (si es necesario)
DATABASE_URL=mysql://user:password@host:3306/database

# Claves API (ejemplos)
API_KEY=your_secret_api_key
SECRET_KEY=your_secret_key_for_jwt

Imagen

  1. Haga clic en Crear o Guardar

⚠️ Importante:

  • Sin espacios alrededor del =
  • Sin comillas alrededor de valores simples
  • No compartas nunca este archivo

⚙️ Paso 4: Configurar el Archivo de Inicio

OuiPanel necesita saber qué archivo de Python ejecutar al inicio.

Acceder a los ajustes

  1. En el menú lateral, haz clic en Configuración
  2. Haz clic en Ajustes del servidor

Imagen


Configurar el archivo a ejecutar

Encuentra el campo Archivo a ejecutar (o Main File / Startup File):Imagen

Tu archivo principal Valor a ingresar
app.py app.py
main.py main.py
api.py api.py
src/app.py src/app.py

⚠️ Importante: El nombre debe coincidir exactamente con tu archivo (distingue mayúsculas de minúsculas).


🚀 Paso 5: Iniciar la API

Iniciar el servidor

  1. En el menú lateral, haz clic en Consola
  2. Haz clic en Iniciar

Instalación automática de dependencias

En el primer inicio, el servidor instala automáticamente los paquetes:

Flask:

Installing requirements from requirements.txt...
Successfully installed flask-3.0.0 python-dotenv-1.0.0 gunicorn-21.2.0

Running app.py...
 * Running on http://0.0.0.0:25639

FastAPI:

Installing requirements from requirements.txt...
Successfully installed fastapi-0.109.0 uvicorn-0.27.0 python-dotenv-1.0.0

Running app.py...
INFO:     Uvicorn running on http://0.0.0.0:25639

✅ Paso 6: Probar la API

Obtener la dirección

  1. Toma nota del puerto mostrado en la consola (ej: 25639)
  2. Obtén la IP de tu servidor en la Vista Global
  3. La dirección de tu API es: http://IP:PUERTO

Ejemplo: http://51.77.xxx.xxx:25639

Imagen

Imagen

Probar los endpoints

Con un navegador:

  • Abre http://51.77.xxx.xxx:25639/ → Debería mostrar el JSON de bienvenida
  • Abre http://51.77.xxx.xxx:25639/health → Comprobación de estado
  • (FastAPI) Abre http://51.77.xxx.xxx:25639/docs → Documentación Swagger

Con curl:

# GET - Página de inicio
curl http://51.77.xxx.xxx:25639/

# GET - Lista de elementos
curl http://51.77.xxx.xxx:25639/api/items

# GET - Un elemento específico
curl http://51.77.xxx.xxx:25639/api/items/1

# POST - Crear un elemento
curl -X POST http://51.77.xxx.xxx:25639/api/items \
  -H "Content-Type: application/json" \
  -d '{"name": "Nuevo elemento", "price": 29.99}'

# PUT - Modificar un elemento
curl -X PUT http://51.77.xxx.xxx:25639/api/items/1 \
  -H "Content-Type: application/json" \
  -d '{"name": "Elemento modificado", "price": 39.99}'

# DELETE - Eliminar un elemento
curl -X DELETE http://51.77.xxx.xxx:25639/api/items/1

Con Postman / Insomnia:

  • Importa la URL base: http://51.77.xxx.xxx:25639
  • Prueba tus diferentes endpoints

Imagen


🌐 Paso 7: Configurar un Nombre de Dominio (Proxy Manager)

Para acceder a tu API a través de una URL limpia con HTTPS (ej: https://api.monsite.com), utiliza el Proxy Manager.

Configurar el DNS

  1. En OuiPanelProxy Manager, toma nota de la IP del Proxy
  2. En tu registrador (OVH, Cloudflare, etc.), crea un registro DNS:
Tipo Nombre Valor
A api IP del Proxy

Agregar el dominio en OuiPanel

  1. En el menú lateral, haz clic en Proxy Manager
  2. Haz clic en Agregar
  3. Rellena:
Campo Valor
Nombre de dominio api.monsite.com
Puerto El puerto de tu API (ej: 25639)
SSL ✅ Activado

Imagen

  1. Haz clic en Crear la redirección

Resultado

Tu API ahora es accesible a través de:

  • https://api.monsite.com (con HTTPS automático)
  • ✅ Certificado SSL gratuito (Let's Encrypt)

Ejemplo de llamada:

curl https://api.monsite.com/api/items

📖 Consulta la guía "Configurar un Nombre de Dominio con el Proxy Manager" para más detalles.


🗄️ Bonus: Conexión a una Base de Datos

MySQL con Flask (PyMySQL)

Agrega en requirements.txt:

pymysql==1.1.0

Ejemplo de conexión:

import pymysql
import os

# Conexión a MySQL
connection = pymysql.connect(
    host=os.getenv('DB_HOST', 'localhost'),
    user=os.getenv('DB_USER', 'root'),
    password=os.getenv('DB_PASSWORD', ''),
    database=os.getenv('DB_NAME', 'mydb'),
    charset='utf8mb4'
)

# Ejemplo de consulta
with connection.cursor() as cursor:
    cursor.execute("SELECT * FROM items")
    result = cursor.fetchall()

Variables .env a añadir:

DB_HOST=mysql-host.ouiheberg.com
DB_USER=tu_usuario
DB_PASSWORD=tu_contraseña
DB_NAME=tu_base

📖 Consulta la guía "Crear y Gestionar una Base de Datos MySQL" para crear tu base de datos.


🔧 Solución de Problemas

La API no se inicia

❌ Error ✅ Solución
ModuleNotFoundError: No module named 'flask' Verifica requirements.txt y reinicia
ModuleNotFoundError: No module named 'fastapi' Verifica requirements.txt y reinicia
ModuleNotFoundError: No module named 'dotenv' Agrega python-dotenv en requirements.txt
SyntaxError Error en tu código Python

Error "No space left on device" (FastAPI)

Este error ocurre cuando pydantic-core (dependencia de FastAPI) debe compilarse con Rust:

error: No space left on device (os error 28)
ERROR: Failed building wheel for pydantic-core
✅ Soluciones
1. Utilice Flask en su lugar (no requiere compilación)
2. Aumente el almacenamiento de su servidor (se recomiendan 5+ GB)
3. Limpie los archivos temporales y vuelva a intentarlo

💡 Recomendación: Para servidores pequeños con poco almacenamiento, Flask es más adecuado que FastAPI.


La API se inicia pero no es accesible

❌ Causa ✅ Solución
Escucha en localhost Cambie a 0.0.0.0
Puerto incorrecto Utilice os.getenv('SERVER_PORT')

Verifique su código:

# ❌ INCORRECTO - escucha solo localmente
app.run(host='localhost', port=5000)
app.run(host='127.0.0.1', port=5000)

# ✅ CORRECTO - escucha en todas las interfaces
app.run(host='0.0.0.0', port=port)
uvicorn.run(app, host='0.0.0.0', port=port)

Error 502 Bad Gateway (Proxy Manager)

❌ Causa ✅ Solución
API no iniciada Inicie el servidor en OuiPanel
Puerto incorrecto en Proxy Manager Verifique el puerto configurado
API caída Consulte la Consola

El archivo .env no se está leyendo

❌ Causa ✅ Solución
python-dotenv no instalado Verifique requirements.txt
load_dotenv() no llamado Agregue load_dotenv() al inicio del archivo
Archivo mal nombrado El archivo debe llamarse exactamente .env

Error CORS

Si llama a su API desde un frontend (React, Vue, etc.):

❌ Error ✅ Solución
Access-Control-Allow-Origin Agregue Flask-CORS o CORSMiddleware (ver sección Seguridad)

🔒 Seguridad

Archivo .env

✅ Por hacer ❌ No hacer
Crear el .env en el servidor Subir el .env desde su PC
Agregar .env al .gitignore Hacer commit del .env en GitHub
Usar variables para secretos Poner las claves API en el código

Prácticas recomendadas de API

  • Valide siempre las entradas de usuario
  • ✅ Use HTTPS en producción (Proxy Manager)
  • ✅ No exponga los errores detallados en producción
  • ✅ Agregue una autenticación para rutas sensibles

Activar CORS (si es necesario)

Si su API es llamada desde un frontend (React, Vue, etc.) en otro dominio:

Flask - Agregue flask-cors:

# requirements.txt
flask-cors==4.0.0
from flask_cors import CORS
app = Flask(__name__)
CORS(app)

FastAPI - El middleware ya está disponible:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

📂 Estructura Avanzada (Recomendada)

Para una API más compleja, organice su código:

📁 MonAPI/
├── 📄 app.py               ← Punto de entrada
├── 📄 requirements.txt
├── 📄 .env
├── 📁 routes/
│   ├── 📄 __init__.py
│   ├── 📄 items.py         ← Rutas /api/items
│   └── 📄 users.py         ← Rutas /api/users
├── 📁 models/
│   └── 📄 item.py          ← Modelo Item
└── 📁 utils/
    └── 📄 helpers.py       ← Funciones utilitarias

💡 Para APIs grandes, esta estructura ayuda a organizar mejor el código y facilita el mantenimiento.


📝 Resumen

1. Elegir el framework (Flask o FastAPI)
2. Preparar los archivos (app.py + requirements.txt con python-dotenv)
3. Asegurarse de que el servidor escuche en 0.0.0.0:PUERTO
4. Subir los archivos a OuiPanel (sin el .env)
5. Crear el archivo .env en el servidor
6. Configurar el archivo de inicio (app.py, main.py...)
7. Iniciar el servidor
8. Probar a través de http://IP:PUERTO
9. (Opcional) Configurar el Proxy Manager para HTTPS

ENDPOINTS DE PRUEBA:
├── GET  /              → Página de inicio
├── GET  /health        → Verificación de estado
├── GET  /api/items     → Lista de items
├── GET  /api/items/1   → Un item
├── POST /api/items     → Crear un item
├── PUT  /api/items/1   → Modificar un item
└── DELETE /api/items/1 → Eliminar un item

(FastAPI) Documentación automática:
├── /docs   → Interfaz Swagger
└── /redoc  → ReDoc