Software Consulting Services

Reflex: Framework fullstack en Python para desarrollos web ágiles y escalables

Tags: Tecnologías
reflex python

 

REFLEX es un framework open source, que puedes usar en Python y sirve para crear, desplegar facil y rapido aplicaciones web.

 

Se pueden crear aplicaciones en minutos, es flexible y se puede utilizar para crear aplicaciones con manejo de usuarios, permisos, roles, navegación, paneles de control o manejo de reportes y formularios. Reflex cuenta con la ventaja de facilitar el acceso a los datos y estados de las variables porque permite el desarrollo full stack, es decir, se puede trabajar al mismo tiempo el backend y el frontend.

 

Es recomendable utilizar entornos virtuales python como venv.

 

Ejemplo :

 

$ python -m venv .venv
$ source .venv/bin/activate
$ pip install reflex
$ reflex init
$ reflex run

 

FRONTEND

 

Importamos la librería Reflex en un archivo python como por ejemplo main.py

 

import reflex as rx

def index():
    return rx.hstack(
         rx.heading("Hola Mundo!", font_size="2em"),        
        spacing="4",
    )

app = rx.App()
app.add_page(index)

 

Con el comando:

 

$ reflex run

 

Ejecutamos la aplicación, Reflex compila el frontend en una aplicación Next.js de una sola página y la sirve en un puerto (por defecto 3000) al que puedes acceder en tu navegador. La función del frontend es reflejar el estado de la aplicación y enviar eventos al backend cuando el usuario interactúa con la interfaz de usuario.

 

No se utiliza un lenguaje de plantillas que combina HTML y Python, solo utilizamos funciones de Python para definir la interfaz de usuario. El siguiente ejemplo nos permite visualizar cómo declarando funciones python creamos un componente para luego ser compilado y convertido en un componente de React:

 

def index():
    return rx.hstack(
        rx.link(
            rx.avatar(src=GithubState.profile_image),
            href=GithubState.url,
        ),
        rx.input(
            placeholder="Your Github username",
            on_blur=GithubState.set_profile,
        ),
    )

 

Después de ejecutar el comando reflex run, se compila el componente anterior en un componente React

 

<HStack>
    <Link href={GithubState.url}>
        <Avatar src={GithubState.profile_image}/>
    </Link>
    <Input
        placeholder="Your Github username"
        // This would actually be a websocket call to the backend.
        onBlur={GithubState.set_profile}
    />
</HStack>

 

Importante: Con reflex es fácil trabajar el estilo y diseńo de la aplicación

 

rx.text("Hello World!", color="blue", font_size="1.5em")

 

Los componentes Reflex pueden diseñarse utilizando todo el poder de CSS. Utiliza la biblioteca Emotion para permitir el diseño "CSS en Python" esto ya lo trae por defecto al momento de compilar (https://emotion.sh/docs/introduction), de modo que pueda pasar cualquier propiedad CSS como argumento de palabra clave a un componente. Esto incluye propiedades responsivas al pasar una lista de valores.

 

Backend

 

En Reflex, solo el frontend se compila en Javascript y se ejecuta en el navegador del usuario, mientras que todo el estado y la lógica permanecen en Python y se ejecutan en el servidor. Cuando iniciamos un servidor FastAPI (por defecto en el puerto 8000) al que se conecta el frontend a través de un websocket (https://fastapi.tiangolo.com/).

 

El estado y lógica se definen dentro de una clase llamada State por ejemplo.

 

class GithubState(rx.State):
    url: str = "https://github.com/reflex-dev"
    profile_image: str = (
        "https://avatars.githubusercontent.com/u/104714959"
    )

    def set_profile(self, username: str):
        if username == "":
            return
        github_data = requests.get(
            f"https://api.github.com/users/{username}"
        ).json()
        self.url = github_data["url"]
        self.profile_image = github_data["avatar_url"]

 

El estado se compone de variables y controladores de eventos,

 

Las variables son valores de la aplicación que pueden cambiar con el tiempo. Se definen como atributos de clase en la clase state y pueden ser cualquier tipo de Python que se pueda serializar en JSON.. Los controladores de eventos son métodos de la clase State que se invocan cuando el usuario interactúa con la interfaz de usuario. Son la única forma en que podemos modificar las variables en Reflex y se pueden invocar en respuesta a las acciones del usuario, como hacer clic en un botón o escribir en un cuadro de texto.

 

Dado que los controladores de eventos se ejecutan en el backend, puedes usar cualquier biblioteca de Python dentro de ellos. En el ejemplo, usamos request para realizar una llamada API a Github para obtener la imagen de perfil del usuario.

 

Razones para tener en cuenta Reflex

 

  1. Unificación del stack en Python
    Reflex integra el desarrollo frontend y backend en un solo lenguaje: Python. Esto reduce la complejidad al evitar el manejo de múltiples tecnologías (por ejemplo, React para el frontend y Flask para el backend). Como proceso interno Reflex compila el código Python del frontend en una aplicación Next.js basada en React y genera un backend con FastAPI quien le permite llamar y comunicar el estado de sus variables y componentes, esta api es de uso interno del proceso que genera la aplicación en Next.js.
  2. Simplicidad y rapidez en el desarrollo
    Con Reflex, puedes definir interfaces de usuario mediante funciones Python y componentes predefinidos, lo que acelera la creación de prototipos y aplicaciones. Por ejemplo, un formulario o un dashboard interactivo se construye con unas pocas líneas de código declarativo. Además, su enfoque "batteries included" incluye manejo de estado con WebSockets para aplicaciones en tiempo real, eliminando la necesidad de configurar APIs manualmente para conectar frontend y backend basado en su mismo contexto, por eso el uso y llamados del State en cada uno de sus contextos de los componentes o páginas.
  3. Despliegue con un solo comando
    Una de las características más destacadas de Reflex es su comando reflex deploy, que permite subir tu aplicación a la nube de Reflex sin preocuparte por detalles de infraestructura como configuración de servidores, SSL o escalabilidad.
  4. Flexibilidad y extensibilidad
    A pesar de su simplicidad, Reflex no sacrifica potencia. Permite integrar componentes React personalizados encapsulados como clases Python, lo que te da acceso al ecosistema de JavaScript si lo necesitas, sin salir de tu entorno Python. Esto lo hace adaptable tanto para aplicaciones pequeñas (como visualizaciones de datos) como para proyectos más complejos (como plataformas multi-páginas).
  5. Integración con el ecosistema Python
    Reflex se beneficia de la compatibilidad con librerías populares de Python como Pandas, NumPy o Matplotlib, lo que lo convierte en una opción sobresaliente para aplicaciones enfocadas en datos, como dashboards o herramientas analíticas. Además, incluye un ORM ligero basado en SQLAlchemy para interactuar con bases de datos SQL (SQLite, PostgreSQL, MySQL), facilitando la persistencia de datos sin dependencias externas pesadas.
  6. Escalabilidad técnica
    El uso de FastAPI en el backend asegura un rendimiento sólido y soporte para programación asíncrona, mientras que la arquitectura de Next.js en el frontend optimiza la carga de páginas y la experiencia del usuario.
  7. Comunidad y evolución activa
    Como proyecto de código abierto bajo la licencia Apache 2.0, Reflex tiene una comunidad creciente (más de 20k estrellas en GitHub a finales de 2024) y recibe actualizaciones frecuentes. Esto asegura que el framework madure con el tiempo, incorpore nuevas características y corrija limitaciones, como su ecosistema de plugins aún en desarrollo comparado con frameworks más establecidos como Django.

 

Casos de uso ideales

 

  • Prototipado rápido: Perfecto para startups o hackathons donde necesitas una aplicación funcional en horas.
  • Aplicaciones de datos: Su integración con librerías científicas de Python lo hace ideal para visualizaciones o análisis.
  • Equipos Python-centrados: Reduce la necesidad de especialistas en frontend, unificando el desarrollo en un solo equipo.

 

Ejemplo rápido:

 

Hagamos un contador… que aumenta y disminuye en su valor

 

Frontend

 

Componente visual que se encuentra resaltado, es decir la aplicación gráfica que le permite a los usuarios interactuar, tanto los títulos botones como una página completa que contiene varios componentes

 

import reflex as rx

class State(rx.State):
    count: int = 0

    def increment(self):
        self.count += 1

    def decrement(self):
        self.count -= 1

def index():
    return rx.hstack(
        rx.button(
            "Decrement",
            color_scheme="ruby",
            on_click=State.decrement,
        ),
        rx.heading(State.count, font_size="2em"),
        rx.button(
            "Increment",
            color_scheme="grass",
            on_click=State.increment,
        ),
        spacing="4",
    )
app = rx.App()
app.add_page(index)

 

Backend (la clase State)

 

Es ese lugar donde declaramos la clase que maneja el estado de nuestras variables y métodos que las afectan como el aumentar o disminuir el valor

 

La variable count es compartida bajo el mismo contexto del estado (como se puede evidenciar al usar su valor y métodos en el ejemplo del código anterior del Frontend). Para acceder y modificar el valor de la variable del estado count es por medio de los métodos o también conocidos Event Handlers.

 

Estado

 

class State(rx.State):
    count: int = 0

 

El estado define todas las variables (llamadas vars ) en una aplicación que pueden cambiar, así como las funciones (llamadas event_handlers ) que las cambian.

 

Aquí nuestro estado tiene una única variable, count, que contiene el valor actual del contador. Lo inicializamos en 0.

 

Controladores de eventos

 

def increment(self):
        self.count += 1

def decrement(self):
        self.count -= 1

 

Dentro del estado, definimos funciones, llamadas controladores de eventos , que cambian las variables de estado. Los controladores de eventos son la única forma de modificar el estado en Reflex. Se pueden llamar en respuesta a acciones del usuario, como hacer clic en un botón o escribir en un cuadro de texto. Estas acciones se denominan eventos.

 

La aplicación de contador tiene dos controladores de eventos increment decrement.

 

Interfaz de usuario (FRONT UI)

 

def index():
    return rx.hstack(
        rx.button(
            "Decrement",
            color_scheme="ruby",
            on_click=State.decrement,
        ),
        rx.heading(State.count, font_size="2em"),
        rx.button(
            "Increment",
            color_scheme="grass",
            on_click=State.increment,
        ),
        spacing="4",
    )

 

Esta función define la interfaz de usuario de la aplicación.

 

Usamos diferentes componentes como rx.hstack, rx.button, y rx.heading para crear la interfaz. Los componentes se pueden anidar para crear diseños complejos y se les puede aplicar estilo utilizando todo el poder de CSS.