microdot — framework HTTP minimalista

Microdot es un framework HTTP pequeño, inspirado en Flask, para MicroPython. Se ejecuta sobre asyncio, gestiona múltiples clientes concurrentes sin hilos y expone una API familiar de decoradores de rutas. Una aplicación mínima tiene este aspecto:

from microdot import Microdot

app = Microdot()

@app.route('/')
async def index(request):
    return 'Hello, world!'

app.run(host='0.0.0.0', port=80)

class Microdot

class microdot.Microdot

Una instancia de aplicación HTTP. Se construye una instancia cerca del comienzo del script y se decora con manejadores de rutas; al llamar a run() o esperar a start_server() comienza el servicio.

Registro de rutas

route(url_pattern: str, methods: list | None = None) Callable

Decorador que registra un manejador para url_pattern bajo los métodos HTTP indicados (por defecto ['GET']). Devuelve el decorador que, al aplicarse a una función, la registra como manejador y devuelve la función sin cambios.

url_pattern

Un patrón de ruta. Admite segmentos estáticos (/users) y segmentos dinámicos delimitados por < / >. Los segmentos dinámicos aceptan un prefijo de tipo opcional separado por :<int:id>, <path:rest>, <re:[0-9a-f]+:hex>. El tipo por defecto es string.

methods

Lista de nombres de métodos HTTP. Si se omite, solo se compara GET.

El manejador se llama primero con el objeto de la solicitud y luego con los segmentos dinámicos capturados como argumentos de palabra clave. El valor de retorno del manejador se convierte en la respuesta HTTP: una Response, una cadena, una tupla (body, status_code[, headers]), o un dict / list (enviado como JSON).

get(url_pattern: str) Callable

Alias de conveniencia para route(url_pattern, methods=['GET']) – registra la función decorada como un manejador GET para url_pattern. Devuelve el decorador.

post(url_pattern: str) Callable

Alias de conveniencia para route(url_pattern, methods=['POST']) – registra la función decorada como un manejador POST para url_pattern. Devuelve el decorador.

put(url_pattern: str) Callable

Alias de conveniencia para route(url_pattern, methods=['PUT']) – registra la función decorada como un manejador PUT para url_pattern. Devuelve el decorador.

patch(url_pattern: str) Callable

Alias de conveniencia para route(url_pattern, methods=['PATCH']) – registra la función decorada como un manejador PATCH para url_pattern. Devuelve el decorador.

delete(url_pattern: str) Callable

Alias de conveniencia para route(url_pattern, methods=['DELETE']) – registra la función decorada como un manejador DELETE para url_pattern. Devuelve el decorador.

Hooks del ciclo de vida

before_request(f: Callable) Callable

Decorador que registra f para ejecutarse antes de cada solicitud. f toma el objeto de la solicitud; su valor de retorno normalmente se ignora. Para cortocircuitar la solicitud, devuelve una Response (o un valor que se convierta en una) – el resto del pipeline se omite entonces y se envía esa respuesta. Devuelve f sin cambios.

after_request(f: Callable) Callable

Decorador que registra f para ejecutarse después de cada solicitud exitosa. f toma (request, response) y debe devolver el objeto de respuesta (posiblemente modificado). Devuelve f sin cambios.

after_error_request(f: Callable) Callable

Decorador que registra f para ejecutarse después de que Microdot genere una respuesta de error (404, 500, excepción lanzada, etc.). f toma (request, response) y debe devolver el objeto de respuesta (posiblemente modificado). Devuelve f sin cambios.

errorhandler(status_code_or_exception_class) Callable

Decorador que registra un manejador personalizado para un código de estado HTTP o una clase de excepción de Python. Para los códigos de estado, el manejador toma solo la solicitud; para las clases de excepción, (request, exception). Devuelve el decorador.

Montaje y aborto

mount(subapp: Microdot, url_prefix: str = '', local: bool = False) None

Adjunta las rutas de otra instancia Microdot bajo url_prefix. Cuando local es False (por defecto), los manejadores before / after / error de la subaplicación también se adjuntan al padre. Cuando es True, esos manejadores se ejecutan solo para las rutas de la subaplicación. Devuelve None.

static abort(status_code: int, reason: str | None = None) None

Lanza HTTPException para abortar la solicitud actual con el código de estado dado. Nunca retorna de forma normal – el framework captura la excepción y la convierte en la respuesta de error correspondiente. Cómodo dentro de los cuerpos de las rutas:

from microdot import abort

@app.get('/users/<int:id>')
def get_user(request, id):
    user = lookup(id)
    if user is None:
        abort(404)
    return user.to_dict()

Ejecución del servidor

run(host: str = '0.0.0.0', port: int = 5000, debug: bool = False, ssl=None) None

Bloquea el hilo que llama, ejecuta asyncio.run() sobre start_server(). Devuelve None solo después de que se haya llamado a shutdown() y el bucle de escucha salga. La forma más sencilla de lanzar una aplicación independiente:

app.run(host='0.0.0.0', port=80)
async start_server(host: str = '0.0.0.0', port: int = 5000, debug: bool = False, ssl=None, start_serving: bool = True) None

Inicia el servidor como una corrutina. Usa esto al integrarlo con un bucle de eventos asyncio existente junto con otras tareas. La corrutina no retorna hasta que se llama a shutdown():

async def main():
    await asyncio.gather(
        app.start_server(port=80),
        capture_loop(),
    )
host

Interfaz de red en la que escuchar. '0.0.0.0' (por defecto) significa todas las interfaces; '127.0.0.1' significa solo loopback.

port

Puerto TCP en el que escuchar. Por defecto 5000 – elige 80 para HTTP simple, 443 para HTTPS.

debug

Si es True, registra cada solicitud y vuelca los trazados de pila a stdout.

ssl

Un ssl.SSLContext para envolver las conexiones entrantes en TLS. None (por defecto) significa HTTP simple.

start_serving

Solo relevante en CPython; se ignora en MicroPython.

shutdown() None

Solicita un apagado ordenado del servidor. Es seguro llamarlo desde un manejador de ruta – la solicitud actual se completa antes de que el bucle salga. Retorna de inmediato; el apagado real ocurre una vez que termina la solicitud en curso.

Atributos

url_map: list

Lista de rutas registradas como tuplas (methods, URLPattern, handler, url_prefix, subapp).

before_request_handlers: list

Lista de invocables registrados con before_request(), en orden de registro. Cada uno se ejecuta con el objeto de la solicitud antes del manejador de ruta. Mutar la lista directamente funciona pero rara vez es necesario – es preferible el decorador.

after_request_handlers: list

Lista de invocables registrados con after_request(), en orden de registro. Cada uno se ejecuta con (request, response) después de una solicitud exitosa y debe devolver la respuesta (posiblemente modificada).

after_error_request_handlers: list

Lista de invocables registrados con after_error_request(), en orden de registro. Cada uno se ejecuta con (request, response) después de que se genera una respuesta de error (por el framework o por un manejador de errores de la aplicación) y debe devolver la respuesta.

error_handlers: dict

Mapeo de claves de error a invocables manejadores, poblado por errorhandler(). Las claves son códigos de estado HTTP (int) o clases de excepción de Python; los valores son los manejadores registrados. Los manejadores de códigos de estado toman (request); los manejadores de clases de excepción toman (request, exception).

debug: bool

True mientras el servidor se ejecuta con debug=True.

class Request

class microdot.Request

Una solicitud HTTP entrante. Las instancias se pasan a los manejadores de ruta como primer argumento posicional. Las aplicaciones no construyen Request directamente.

Atributos de clase

max_content_length: int

Rechaza con una respuesta 413 las solicitudes cuyo Content-Length supere esta cantidad de bytes. Por defecto 16 KB.

max_body_length: int

El cuerpo más grande que se almacena en memoria y se expone a través de body. Los cuerpos más grandes (hasta max_content_length) permanecen en el socket y deben leerse a través de stream. Por defecto 16 KB.

max_readline: int

Longitud máxima de una sola línea de solicitud / línea de cabecera en bytes. Por defecto 2 KB.

Atributos de instancia

app: Microdot

La instancia Microdot que gestiona la solicitud.

client_addr: tuple

La dirección del cliente como (host, port).

method: str

Cadena del método HTTP ('GET', 'POST', …).

scheme: str

'http' o 'https'.

url: str

La ruta y cadena de consulta completas de la URL de la solicitud (todo lo que va después del host).

path: str

Solo la porción de la ruta.

query_string: str | None

La porción cruda de la cadena de consulta, o None.

args: MultiDict

Cadena de consulta analizada como un MultiDict.

headers: NoCaseDict

Cabeceras de la solicitud como un NoCaseDict (búsqueda sin distinción de mayúsculas/minúsculas).

cookies: dict

Cabecera Cookie analizada como un dict.

content_length: int

El valor entero de Content-Length, o 0 si está ausente.

content_type: str | None

El valor de la cabecera Content-Type, o None.

g: object

Un contenedor de formato libre por solicitud (un objeto vacío). Asigna atributos a él para pasar valores entre los hooks y los manejadores (request.g.user = ...).

route: Callable

La función manejadora que coincidió con esta solicitud.

url_prefix: str

Prefijo bajo el que se montó la ruta, o ''.

subapp: Microdot | None

La instancia de la subaplicación montada, o None.

Acceso al cuerpo

body: bytes

El cuerpo completo de la solicitud como bytes. Vacío cuando el cuerpo se está transmitiendo en streaming (ver stream).

stream: object

Un objeto de stream asíncrono que expone read() sobre el cuerpo. Úsalo para cuerpos más grandes que max_body_length.

json: dict | list | str | int | float | bool | None

El cuerpo analizado como JSON (un dict, list, str, int, float o bool – lo que codifique la carga útil), o None si el Content-Type no es application/json.

form: MultiDict | None

Campos de formulario codificados en URL como un MultiDict, o None. Para multipart/form-data, decora la ruta con microdot.multipart.with_form_data().

files: dict | None

Archivos subidos como {name: FileUpload}, poblado por microdot.multipart.with_form_data(). Es None hasta que se ejecuta ese decorador.

after_request(f: Callable) Callable

Registra un hook after-request local a la solicitud – se ejecuta después de los manejadores after-request a nivel de aplicación, solo en caso de éxito. f toma (request, response) y debe devolver el objeto de respuesta (posiblemente modificado). Devuelve f sin cambios.

class Response

class microdot.Response(body=b'', status_code: int = 200, headers: dict | None = None, reason: str | None = None)

Una respuesta HTTP. La mayoría de los manejadores devuelven valores que Microdot convierte automáticamente en una Response; constrúyela directamente cuando necesites cabeceras personalizadas o un código de estado específico.

body

Cuerpo de la respuesta. str se codifica en UTF-8; dict / list se codifica como JSON y el Content-Type se establece en consecuencia; bytes se envía tal cual; un objeto tipo archivo o un generador asíncrono se transmiten en streaming.

status_code

Estado HTTP numérico. Por defecto 200.

headers

Dict de cabeceras de respuesta (sin distinción de mayúsculas/minúsculas).

reason

Frase de motivo personalizada. Por defecto es "OK" para 200 y "N/A" en caso contrario.

Atributos de clase

default_content_type: str

Content-Type usado cuando no se establece ninguno explícitamente. Por defecto 'text/plain'.

default_send_file_max_age: int | None

Valor de Cache-Control: max-age para send_file() cuando no se proporciona max_age. None (por defecto) significa sin cabecera Cache-Control.

send_file_buffer_size: int

Tamaño de fragmento para el streaming de send_file(). Por defecto 1024.

already_handled: None

Centinela devuelto por los manejadores que ya han escrito la respuesta directamente (usado por las actualizaciones a WebSocket). Siempre None; lo que importa es la identidad.

types_map: dict

Mapa de extensión a tipo MIME usado por send_file() para inferir el tipo de contenido. Mapea css, gif, html, jpg, js, json, png, txt, svg.

Métodos

Añade una cabecera Set-Cookie. expires puede ser una cadena ya formateada o un objeto similar a datetime con timetuple(). Devuelve None; la cabecera se añade a esta respuesta en el sitio.

Establece un Set-Cookie que expira inmediatamente la cookie dada. kwargs acepta las mismas opciones que set_cookie() (path, domain, secure, http_only, partitioned); expires y max_age se ignoran. Devuelve None; la cabecera se añade a esta respuesta en el sitio.

classmethod redirect(location: str, status_code: int = 302) Response

Devuelve una respuesta de redirección:

@app.get('/old')
def old(request):
    return Response.redirect('/new')
classmethod send_file(filename: str, status_code: int = 200, content_type: str | None = None, stream=None, max_age: int | None = None, compressed: bool | str = False, file_extension: str = '') Response

Transmite en streaming un archivo del sistema de archivos como cuerpo de la respuesta. content_type se infiere de la extensión a través de types_map si no se proporciona. compressed=True establece Content-Encoding: gzip (el archivo ya debe estar comprimido).

Advertencia

filename se abre directamente. Nunca pases una ruta proporcionada por el usuario sin sanear – hacerlo permite la divulgación arbitraria de archivos.

Excepciones

exception microdot.HTTPException

Lanzada por abort() para cortocircuitar una solicitud con un código de estado específico. Microdot la captura y la convierte en la respuesta de error correspondiente.

status_code: int

Código de estado HTTP numérico a devolver – el valor pasado a abort().

reason: str

Frase de motivo a incluir en la respuesta de error. Si no se proporciona a abort(), por defecto es "<status_code> error" (p. ej. "404 error").

class URLPattern

class microdot.URLPattern(url_pattern: str)

La forma compilada del patrón de URL de una ruta. Construida automáticamente por Microdot.route(); las aplicaciones rara vez instancian una directamente.

classmethod register_type(type_name: str, pattern: str = '[^/]+', parser: Callable | None = None) None

Registra un nuevo tipo de segmento dinámico para usar en los patrones de ruta. Devuelve None; el tipo se añade al registro de tipos a nivel de clase. Por ejemplo, para añadir un tipo <uuid:...>:

URLPattern.register_type('uuid', '[0-9a-f-]{36}')

parser es un invocable opcional que convierte la cadena capturada antes de que llegue al manejador.

match(path: str) dict | None

Compara path con el patrón y devuelve un dict de los grupos capturados, o None si no hay coincidencia.

Clases auxiliares

class microdot.MultiDict(initial_dict: dict | None = None)

Una subclase de dict que almacena múltiples valores por clave. Se usa para las cadenas de consulta y los cuerpos de formulario codificados en URL donde la misma clave puede aparecer más de una vez (?tag=a&tag=b).

get(key, default=None, type: Callable | None = None)

Devuelve el primer valor para key, opcionalmente convertido con type (un invocable). Devuelve default si la clave falta o la conversión falla; en caso contrario devuelve el valor (opcionalmente convertido).

getlist(key, type: Callable | None = None) list

Devuelve todos los valores para key como una lista, opcionalmente con cada valor convertido por type. Devuelve una lista vacía si key no está presente.

class microdot.NoCaseDict

Una subclase de dict con claves de cadena sin distinción de mayúsculas/minúsculas. Se usa para Request.headers y Response.headers.

Funciones a nivel de módulo

microdot.abort(status_code: int, reason: str | None = None) None

Atajo para Microdot.abort(). Nunca retorna de forma normal – lanza HTTPException. Importable como from microdot import abort.

microdot.redirect(location: str, status_code: int = 302) Response

Atajo para Response.redirect(). Importable como from microdot import redirect.

microdot.send_file(filename: str, **kwargs) Response

Atajo para Response.send_file().

microdot.urlencode(s: str) str

Codifica en porcentaje un componente de URL. Reemplaza los caracteres que tienen un significado reservado en una URL (/, ?, &, =, #, espacio, …) con sus escapes hexadecimales %xx para que el resultado pueda situarse de forma segura dentro de un segmento de ruta o un valor de consulta. Devuelve el str codificado.

microdot.urldecode(s: str) str

Decodifica en porcentaje un componente de URL – el inverso de urlencode(). Los escapes %xx se reemplazan por el byte que codifican, y + se convierte en un espacio (la convención histórica de las cadenas de consulta). Devuelve el str decodificado.

Submódulos