microdot — framework HTTP minimale

Microdot è un piccolo framework HTTP per MicroPython ispirato a Flask. Funziona sopra asyncio, gestisce più client concorrenti senza thread ed espone una familiare API basata su decoratori di route. Un’applicazione minimale ha questo aspetto:

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

Un’istanza di applicazione HTTP. Si costruisce un’istanza vicino all’inizio dello script e la si decora con gli handler delle route; chiamando run() o attendendo start_server() inizia il servizio.

Registrazione delle route

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

Decoratore che registra un handler per url_pattern sotto i metodi HTTP elencati (predefinito ['GET']). Restituisce il decoratore che, quando applicato a una funzione, la registra come handler e restituisce la funzione invariata.

url_pattern

Un pattern di percorso. Supporta segmenti statici (/users) e segmenti dinamici racchiusi tra < / >. I segmenti dinamici accettano un prefisso di tipo opzionale separato da :<int:id>, <path:rest>, <re:[0-9a-f]+:hex>. Il tipo predefinito è string.

methods

Elenco di nomi di metodi HTTP. Se omesso, viene confrontato solo GET.

L’handler viene chiamato prima con l’oggetto request, poi con gli eventuali segmenti dinamici catturati come argomenti keyword. Il valore di ritorno dell’handler diventa la risposta HTTP: una Response, una stringa, una tupla (body, status_code[, headers]) o un dict / list (inviato come JSON).

get(url_pattern: str) Callable

Alias di comodità per route(url_pattern, methods=['GET']) – registra la funzione decorata come handler GET per url_pattern. Restituisce il decoratore.

post(url_pattern: str) Callable

Alias di comodità per route(url_pattern, methods=['POST']) – registra la funzione decorata come handler POST per url_pattern. Restituisce il decoratore.

put(url_pattern: str) Callable

Alias di comodità per route(url_pattern, methods=['PUT']) – registra la funzione decorata come handler PUT per url_pattern. Restituisce il decoratore.

patch(url_pattern: str) Callable

Alias di comodità per route(url_pattern, methods=['PATCH']) – registra la funzione decorata come handler PATCH per url_pattern. Restituisce il decoratore.

delete(url_pattern: str) Callable

Alias di comodità per route(url_pattern, methods=['DELETE']) – registra la funzione decorata come handler DELETE per url_pattern. Restituisce il decoratore.

Hook del ciclo di vita

before_request(f: Callable) Callable

Decoratore che registra f per l’esecuzione prima di ogni richiesta. f riceve l’oggetto request; il suo valore di ritorno viene normalmente ignorato. Per interrompere anticipatamente la richiesta, restituire una Response (o un valore che si converte in essa) – il resto della pipeline viene quindi saltato e viene inviata quella risposta. Restituisce f invariata.

after_request(f: Callable) Callable

Decoratore che registra f per l’esecuzione dopo ogni richiesta riuscita. f riceve (request, response) e deve restituire l’oggetto response (eventualmente modificato). Restituisce f invariata.

after_error_request(f: Callable) Callable

Decoratore che registra f per l’esecuzione dopo che Microdot genera una risposta di errore (404, 500, eccezione sollevata, ecc.). f riceve (request, response) e deve restituire l’oggetto response (eventualmente modificato). Restituisce f invariata.

errorhandler(status_code_or_exception_class) Callable

Decoratore che registra un handler personalizzato per un codice di stato HTTP o una classe di eccezione Python. Per i codici di stato, l’handler riceve solo la request; per le classi di eccezione, (request, exception). Restituisce il decoratore.

Montaggio e interruzione

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

Collega le route di un’altra istanza Microdot sotto url_prefix. Quando local è False (predefinito), anche gli handler before / after / error della sotto-app vengono collegati al genitore. Quando è True, tali handler vengono eseguiti solo per le route della sotto-app. Restituisce None.

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

Solleva HTTPException per interrompere la richiesta corrente con il codice di stato indicato. Non restituisce mai normalmente – il framework cattura l’eccezione e la trasforma nella corrispondente risposta di errore. Comodo all’interno dei corpi delle route:

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()

Esecuzione del server

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

Blocca il thread chiamante, esegue asyncio.run() su start_server(). Restituisce None solo dopo che shutdown() è stata chiamata e il loop di ascolto è terminato. Il modo più semplice per avviare un’app autonoma:

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

Avvia il server come coroutine. Usare questo quando si integra con un loop di eventi asyncio esistente insieme ad altri task. La coroutine non ritorna finché non viene chiamata shutdown()

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

Interfaccia di rete su cui ascoltare. '0.0.0.0' (predefinito) significa tutte le interfacce; '127.0.0.1' significa solo loopback.

port

Porta TCP su cui ascoltare. Predefinita 5000 – scegliere 80 per HTTP semplice, 443 per HTTPS.

debug

Se True, registra ogni richiesta e scarica i traceback su stdout.

ssl

Un ssl.SSLContext per incapsulare le connessioni in entrata in TLS. None (predefinito) significa HTTP semplice.

start_serving

Rilevante solo su CPython; ignorato su MicroPython.

shutdown() None

Richiede un arresto graduale del server. È sicuro chiamarla da un handler di route – la richiesta corrente viene completata prima che il loop termini. Restituisce immediatamente; l’arresto effettivo avviene una volta terminata la richiesta in corso.

Attributi

url_map: list

Elenco delle route registrate come tuple (methods, URLPattern, handler, url_prefix, subapp).

before_request_handlers: list

Elenco dei callable registrati con before_request(), in ordine di registrazione. Ciascuno viene eseguito con l’oggetto request prima dell’handler della route. Modificare direttamente l’elenco funziona ma è raramente necessario – è preferibile usare il decoratore.

after_request_handlers: list

Elenco dei callable registrati con after_request(), in ordine di registrazione. Ciascuno viene eseguito con (request, response) dopo una richiesta riuscita e deve restituire la risposta (eventualmente modificata).

after_error_request_handlers: list

Elenco dei callable registrati con after_error_request(), in ordine di registrazione. Ciascuno viene eseguito con (request, response) dopo che viene generata una risposta di errore (dal framework o da un handler di errore dell’applicazione) e deve restituire la risposta.

error_handlers: dict

Mappatura di chiavi di errore a callable handler, popolata da errorhandler(). Le chiavi sono codici di stato HTTP (int) oppure classi di eccezione Python; i valori sono gli handler registrati. Gli handler dei codici di stato ricevono (request); gli handler delle classi di eccezione ricevono (request, exception).

debug: bool

True mentre il server è in esecuzione con debug=True.

class Request

class microdot.Request

Una richiesta HTTP in entrata. Le istanze vengono passate agli handler delle route come primo argomento posizionale. Le applicazioni non costruiscono Request direttamente.

Attributi di classe

max_content_length: int

Rifiuta con una risposta 413 le richieste il cui Content-Length supera questo numero di byte. Predefinito 16 KB.

max_body_length: int

Corpo più grande che viene bufferizzato in memoria ed esposto tramite body. I corpi più grandi (fino a max_content_length) rimangono sul socket e devono essere letti tramite stream. Predefinito 16 KB.

max_readline: int

Lunghezza massima in byte di una singola riga di richiesta / riga di header. Predefinito 2 KB.

Attributi di istanza

app: Microdot

L’istanza Microdot che gestisce la richiesta.

client_addr: tuple

L’indirizzo del client come (host, port).

method: str

Stringa del metodo HTTP ('GET', 'POST', …).

scheme: str

'http' o 'https'.

url: str

Il percorso URL completo della richiesta e la query string (tutto ciò che segue l’host).

path: str

Solo la porzione del percorso.

query_string: str | None

La porzione grezza della query string, oppure None.

args: MultiDict

Query string analizzata come MultiDict.

headers: NoCaseDict

Header della richiesta come NoCaseDict (ricerca case-insensitive).

cookies: dict

Header Cookie analizzato come dict.

content_length: int

Il valore intero di Content-Length, o 0 se assente.

content_type: str | None

Il valore dell’header Content-Type, oppure None.

g: object

Un contenitore per-richiesta a forma libera (un oggetto nudo). Assegnargli attributi per passare valori tra hook e handler (request.g.user = ...).

route: Callable

La funzione handler che ha corrisposto a questa richiesta.

url_prefix: str

Prefisso sotto cui è stata montata la route, oppure ''.

subapp: Microdot | None

L’istanza della sotto-app montata, oppure None.

Accesso al corpo

body: bytes

Il corpo completo della richiesta come bytes. Vuoto quando il corpo viene trasmesso in streaming (vedere stream).

stream: object

Un oggetto stream asincrono che espone read() sul corpo. Usare questo per corpi più grandi di max_body_length.

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

Il corpo analizzato come JSON (un dict, list, str, int, float o bool – a seconda di ciò che il payload codifica), oppure None se il Content-Type non è application/json.

form: MultiDict | None

Campi di form codificati in URL come MultiDict, oppure None. Per multipart/form-data, decorare la route con microdot.multipart.with_form_data().

files: dict | None

File caricati come {name: FileUpload}, popolato da microdot.multipart.with_form_data(). None finché quel decoratore non viene eseguito.

after_request(f: Callable) Callable

Registra un hook after-request locale alla richiesta – viene eseguito dopo gli handler after-request a livello di applicazione, solo in caso di successo. f riceve (request, response) e deve restituire l’oggetto response (eventualmente modificato). Restituisce f invariata.

class Response

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

Una risposta HTTP. La maggior parte degli handler restituisce valori che Microdot converte automaticamente in una Response; costruirne una direttamente quando servono header personalizzati o un codice di stato specifico.

body

Corpo della risposta. str viene codificato in UTF-8; dict / list viene codificato in JSON e il Content-Type viene impostato di conseguenza; bytes viene inviato così com’è; un oggetto file-like o un generatore asincrono viene trasmesso in streaming.

status_code

Stato HTTP numerico. Predefinito 200.

headers

Dict di header della risposta (case-insensitive).

reason

Frase di motivazione personalizzata. Predefinita "OK" per 200 e "N/A" altrimenti.

Attributi di classe

default_content_type: str

Content-Type usato quando nessuno è impostato esplicitamente. Predefinito 'text/plain'.

default_send_file_max_age: int | None

Valore Cache-Control: max-age per send_file() quando max_age non è fornito. None (predefinito) significa nessun header Cache-Control.

send_file_buffer_size: int

Dimensione dei chunk per lo streaming di send_file(). Predefinita 1024.

already_handled: None

Sentinella restituita dagli handler che hanno già scritto la risposta direttamente (usata dagli upgrade WebSocket). Sempre None; ciò che conta è l’identità.

types_map: dict

Mappa estensione-a-tipo-mime usata da send_file() per l’inferenza del content-type. Mappa css, gif, html, jpg, js, json, png, txt, svg.

Metodi

Aggiunge un header Set-Cookie. expires può essere una stringa pre-formattata o un oggetto simile a datetime con timetuple(). Restituisce None; l’header viene aggiunto a questa risposta in loco.

Imposta un Set-Cookie che fa scadere immediatamente il cookie indicato. kwargs accetta le stesse opzioni di set_cookie() (path, domain, secure, http_only, partitioned); expires e max_age vengono ignorati. Restituisce None; l’header viene aggiunto a questa risposta in loco.

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

Restituisce una risposta di redirect:

@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

Trasmette in streaming un file dal filesystem come corpo della risposta. content_type viene dedotto dall’estensione tramite types_map se non fornito. compressed=True imposta Content-Encoding: gzip (il file deve essere già compresso).

Avvertimento

filename viene aperto direttamente. Non passare mai un percorso fornito dall’utente non sanificato – farlo consente la divulgazione arbitraria di file.

Eccezioni

exception microdot.HTTPException

Sollevata da abort() per interrompere anticipatamente una richiesta con un codice di stato specifico. Microdot la cattura e la trasforma nella corrispondente risposta di errore.

status_code: int

Codice di stato HTTP numerico da restituire – il valore passato a abort().

reason: str

Frase di motivazione da includere nella risposta di errore. Se non fornita a abort(), predefinita a "<status_code> error" (ad es. "404 error").

class URLPattern

class microdot.URLPattern(url_pattern: str)

La forma compilata del pattern URL di una route. Costruita automaticamente da Microdot.route(); le applicazioni raramente ne istanziano una direttamente.

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

Registra un nuovo tipo di segmento dinamico da usare nei pattern delle route. Restituisce None; il tipo viene aggiunto al registro dei tipi a livello di classe. Ad esempio, per aggiungere un tipo <uuid:...>

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

parser è un callable opzionale che converte la stringa catturata prima che raggiunga l’handler.

match(path: str) dict | None

Confronta path con il pattern e restituisce un dict dei gruppi catturati, oppure None in caso di mancata corrispondenza.

Classi di supporto

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

Una sottoclasse di dict che memorizza più valori per chiave. Usata per le query string e i corpi di form codificati in URL dove la stessa chiave può comparire più di una volta (?tag=a&tag=b).

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

Restituisce il primo valore per key, opzionalmente convertito con type (un callable). Restituisce default se la chiave è mancante o la conversione fallisce; altrimenti restituisce il valore (eventualmente convertito).

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

Restituisce tutti i valori per key come lista, opzionalmente con ogni valore convertito da type. Restituisce una lista vuota se key non è presente.

class microdot.NoCaseDict

Una sottoclasse di dict con chiavi stringa case-insensitive. Usata per Request.headers e Response.headers.

Funzioni a livello di modulo

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

Scorciatoia per Microdot.abort(). Non restituisce mai normalmente – solleva HTTPException. Importabile come from microdot import abort.

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

Scorciatoia per Response.redirect(). Importabile come from microdot import redirect.

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

Scorciatoia per Response.send_file().

microdot.urlencode(s: str) str

Codifica in percent-encoding un componente URL. Sostituisce i caratteri che hanno un significato riservato in un URL (/, ?, &, =, #, spazio, …) con i loro escape esadecimali %xx in modo che il risultato possa stare in sicurezza all’interno di un segmento di percorso o di un valore di query. Restituisce la str codificata.

microdot.urldecode(s: str) str

Decodifica un componente URL in percent-encoding – l’inverso di urlencode(). Gli escape %xx vengono sostituiti con il byte che codificano, e + viene convertito in uno spazio (la convenzione storica delle query string). Restituisce la str decodificata.

Sottomoduli