microdot — minimal HTTP framework¶
Microdot is a small, Flask-inspired HTTP framework for MicroPython. It runs
on top of asyncio, handles multiple concurrent clients without
threads, and exposes a familiar route-decorator API. A minimal application
looks like:
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¶
An HTTP application instance. One instance is constructed near the top of the script and decorated with route handlers; calling
run()or awaitingstart_server()begins serving.Route registration
- route(url_pattern: str, methods: list | None = None) Callable¶
Decorator that registers a handler for url_pattern under the listed HTTP methods (default
['GET']). Returns the decorator that, when applied to a function, registers it as the handler and returns the function unchanged.- url_pattern
A path pattern. Supports static segments (
/users) and dynamic segments enclosed in</>. Dynamic segments accept an optional type prefix separated by:–<int:id>,<path:rest>,<re:[0-9a-f]+:hex>. The default type isstring.- methods
List of HTTP method names. If omitted, only
GETis matched.
The handler is called with the request object first, then any captured dynamic segments as keyword arguments. The handler’s return value becomes the HTTP response: a
Response, a string, a tuple(body, status_code[, headers]), or a dict / list (sent as JSON).
- get(url_pattern: str) Callable¶
Convenience alias for
route(url_pattern, methods=['GET'])– register the decorated function as aGEThandler for url_pattern. Returns the decorator.
- post(url_pattern: str) Callable¶
Convenience alias for
route(url_pattern, methods=['POST'])– register the decorated function as aPOSThandler for url_pattern. Returns the decorator.
- put(url_pattern: str) Callable¶
Convenience alias for
route(url_pattern, methods=['PUT'])– register the decorated function as aPUThandler for url_pattern. Returns the decorator.
- patch(url_pattern: str) Callable¶
Convenience alias for
route(url_pattern, methods=['PATCH'])– register the decorated function as aPATCHhandler for url_pattern. Returns the decorator.
- delete(url_pattern: str) Callable¶
Convenience alias for
route(url_pattern, methods=['DELETE'])– register the decorated function as aDELETEhandler for url_pattern. Returns the decorator.
Lifecycle hooks
- before_request(f: Callable) Callable¶
Decorator that registers f to run before every request. f takes the request object; its return value is normally ignored. To short-circuit the request, return a
Response(or a value that converts to one) – the rest of the pipeline is then skipped and that response is sent. Returns f unchanged.
- after_request(f: Callable) Callable¶
Decorator that registers f to run after every successful request. f takes
(request, response)and must return the (possibly modified) response object. Returns f unchanged.
- after_error_request(f: Callable) Callable¶
Decorator that registers f to run after Microdot generates an error response (404, 500, raised exception, etc.). f takes
(request, response)and must return the (possibly modified) response object. Returns f unchanged.
- errorhandler(status_code_or_exception_class) Callable¶
Decorator that registers a custom handler for an HTTP status code or a Python exception class. For status codes, the handler takes only the request; for exception classes,
(request, exception). Returns the decorator.
Mounting and aborting
- mount(subapp: Microdot, url_prefix: str = '', local: bool = False) None¶
Attach another
Microdotinstance’s routes under url_prefix. When local isFalse(default), the sub-app’s before / after / error handlers are also attached to the parent. WhenTrue, those handlers run only for sub-app routes. ReturnsNone.
- static abort(status_code: int, reason: str | None = None) None¶
Raise
HTTPExceptionto abort the current request with the given status code. Never returns normally – the framework catches the exception and turns it into the corresponding error response. Convenient inside route bodies: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()
Running the server
- run(host: str = '0.0.0.0', port: int = 5000, debug: bool = False, ssl=None) None¶
Block the calling thread, run
asyncio.run()onstart_server(). ReturnsNoneonly aftershutdown()has been called and the listening loop exits. The simplest way to launch a standalone app: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¶
Start the server as a coroutine. Use this when integrating with an existing
asyncioevent loop alongside other tasks. The coroutine does not return untilshutdown()is called:async def main(): await asyncio.gather( app.start_server(port=80), capture_loop(), )
- host
Network interface to listen on.
'0.0.0.0'(default) means all interfaces;'127.0.0.1'means loopback only.- port
TCP port to listen on. Default
5000– pick80for plain HTTP,443for HTTPS.- debug
If
True, log every request and dump tracebacks to stdout.- ssl
An
ssl.SSLContextto wrap incoming connections in TLS.None(default) means plain HTTP.- start_serving
Only relevant on CPython; ignored on MicroPython.
- shutdown() None¶
Request a graceful server shutdown. Safe to call from a route handler – the current request completes before the loop exits. Returns immediately; the actual shutdown happens once the in-flight request finishes.
Attributes
- url_map: list¶
List of registered routes as
(methods, URLPattern, handler, url_prefix, subapp)tuples.
- before_request_handlers: list¶
List of callables registered with
before_request(), in registration order. Each runs with the request object before the route handler. Mutating the list directly works but is rarely needed – prefer the decorator.
- after_request_handlers: list¶
List of callables registered with
after_request(), in registration order. Each runs with(request, response)after a successful request and must return the (possibly modified) response.
- after_error_request_handlers: list¶
List of callables registered with
after_error_request(), in registration order. Each runs with(request, response)after an error response is generated (by the framework or by an application error handler) and must return the response.
- error_handlers: dict¶
Mapping of error keys to handler callables, populated by
errorhandler(). Keys are either HTTP status codes (int) or Python exception classes; values are the registered handlers. Status-code handlers take(request); exception-class handlers take(request, exception).
class Request¶
- class microdot.Request¶
An incoming HTTP request. Instances are passed to route handlers as the first positional argument. Applications do not construct
Requestdirectly.Class attributes
- max_content_length: int¶
Reject requests whose
Content-Lengthexceeds this many bytes with a 413 response. Default 16 KB.
- max_body_length: int¶
Largest body that is buffered into memory and exposed via
body. Larger bodies (up tomax_content_length) remain on the socket and must be read throughstream. Default 16 KB.
Instance attributes
- headers: NoCaseDict¶
Request headers as a
NoCaseDict(case-insensitive lookup).
- g: object¶
A free-form per-request container (a bare object). Assign attributes to it to pass values between hooks and handlers (
request.g.user = ...).
- route: Callable¶
The handler function that matched this request.
Body access
- stream: object¶
An async stream object exposing
read()over the body. Use this for bodies larger thanmax_body_length.
- json: dict | list | str | int | float | bool | None¶
The body parsed as JSON (a
dict,list,str,int,float, orbool– whatever the payload encodes), orNoneif theContent-Typeis notapplication/json.
- form: MultiDict | None¶
URL-encoded form fields as a
MultiDict, orNone. Formultipart/form-data, decorate the route withmicrodot.multipart.with_form_data().
- files: dict | None¶
Uploaded files as
{name: FileUpload}, populated bymicrodot.multipart.with_form_data().Noneuntil that decorator runs.
- after_request(f: Callable) Callable¶
Register a request-local after-request hook – runs after the application-level after-request handlers, only on success. f takes
(request, response)and must return the (possibly modified) response object. Returns f unchanged.
class Response¶
- class microdot.Response(body=b'', status_code: int = 200, headers: dict | None = None, reason: str | None = None)¶
An HTTP response. Most handlers return values that Microdot converts to a
Responseautomatically; construct one directly when you need custom headers or a specific status code.- body
Response body.
stris UTF-8-encoded;dict/listis JSON-encoded and theContent-Typeset accordingly;bytesis sent as-is; a file-like object or async generator streams.- status_code
Numeric HTTP status. Default 200.
- headers
Dict of response headers (case-insensitive).
- reason
Custom reason phrase. Defaults to
"OK"for 200 and"N/A"otherwise.
Class attributes
- default_send_file_max_age: int | None¶
Cache-Control: max-agevalue forsend_file()whenmax_ageis not given.None(default) means no Cache-Control header.
- send_file_buffer_size: int¶
Chunk size for
send_file()streaming. Default 1024.
- already_handled: None¶
Sentinel returned from handlers that have already written the response directly (used by WebSocket upgrades). Always
None; the identity is what matters.
- types_map: dict¶
Extension-to-mime-type map used by
send_file()for content- type inference. Mapscss,gif,html,jpg,js,json,png,txt,svg.
Methods
- set_cookie(cookie: str, value: str, path: str | None = None, domain: str | None = None, expires=None, max_age: int | None = None, secure: bool = False, http_only: bool = False, partitioned: bool = False) None¶
Add a
Set-Cookieheader. expires may be a pre-formatted string or adatetime-like object withtimetuple(). ReturnsNone; the header is appended to this response in place.
- delete_cookie(cookie: str, **kwargs) None¶
Set a
Set-Cookiethat expires the given cookie immediately.kwargsaccepts the same options asset_cookie()(path,domain,secure,http_only,partitioned);expiresandmax_ageare ignored. ReturnsNone; the header is appended to this response in place.
- classmethod redirect(location: str, status_code: int = 302) Response¶
Return a redirect response:
@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¶
Stream a file from the filesystem as the response body.
content_typeis inferred from the extension viatypes_mapif not given.compressed=TruesetsContent-Encoding: gzip(the file must already be compressed).Warning
filename is opened directly. Never pass an unsanitized user-supplied path – doing so allows arbitrary file disclosure.
Exceptions¶
class URLPattern¶
- class microdot.URLPattern(url_pattern: str)¶
The compiled form of a route’s URL pattern. Constructed automatically by
Microdot.route(); applications rarely instantiate one directly.- classmethod register_type(type_name: str, pattern: str = '[^/]+', parser: Callable | None = None) None¶
Register a new dynamic-segment type for use in route patterns. Returns
None; the type is added to the class-level type registry. For example to add a<uuid:...>type:URLPattern.register_type('uuid', '[0-9a-f-]{36}')parser is an optional callable that converts the captured string before it reaches the handler.
Helper classes¶
- class microdot.MultiDict(initial_dict: dict | None = None)¶
A dict subclass that stores multiple values per key. Used for query strings and URL-encoded form bodies where the same key can appear more than once (
?tag=a&tag=b).
- class microdot.NoCaseDict¶
A dict subclass with case-insensitive string keys. Used for
Request.headersandResponse.headers.
Module-level functions¶
- microdot.abort(status_code: int, reason: str | None = None) None¶
Shortcut for
Microdot.abort(). Never returns normally – raisesHTTPException. Importable asfrom microdot import abort.
- microdot.redirect(location: str, status_code: int = 302) Response¶
Shortcut for
Response.redirect(). Importable asfrom microdot import redirect.
- microdot.send_file(filename: str, **kwargs) Response¶
Shortcut for
Response.send_file().
- microdot.urlencode(s: str) str¶
Percent-encode a URL component. Replaces characters that have reserved meaning in a URL (
/,?,&,=,#, space, …) with their%xxhex escapes so the result can safely sit inside a path segment or query value. Returns the encodedstr.
- microdot.urldecode(s: str) str¶
Percent-decode a URL component – the inverse of
urlencode().%xxescapes are replaced with the byte they encode, and+is converted to a space (the historical query-string convention). Returns the decodedstr.
Submodules¶
microdot.auth— HTTP authenticationmicrodot.cors— Cross-Origin Resource Sharingmicrodot.csrf— CSRF protectionmicrodot.login— user login flowmicrodot.multipart— multipart/form-data parsingmicrodot.session— signed cookie sessionsmicrodot.sse— Server-Sent Eventsmicrodot.websocket— WebSocket support