Routing and handlers¶
MicroPie maps incoming HTTP requests to methods on your App
subclass. This section explains how the mapping works and how your
handlers receive input from the URL path, query strings, form data and
sessions.
URL to function mapping¶
When an HTTP request arrives, MicroPie extracts the path portion of the
URL and uses the first path segment to determine which method should
handle the request. For example, a GET request to /greet calls
greet on your App subclass. A request to the
root URL / calls index. Only methods that do not start with
an underscore are exposed as route handlers. Prefacing a method name
with an underscore makes it private and hides it from external
requests.
Handlers may be synchronous or asynchronous functions. They return
either a string, bytes, a JSON‑serialisable object, a tuple of
(status_code, body) or (status_code, body, headers), or an
iterator/generator for streaming responses. See
Streaming responses for details on streaming.
Parameters and arguments¶
MicroPie automatically populates handler arguments from several sources in the following order:
Path parameters – Additional path segments after the first map to positional parameters. For example:
class AppExample(App): async def greet(self, name): return f"Hello, {name}!"
Visiting
/greet/Alicepasses"Alice"as thenameargument. You can also use*argsto capture an arbitrary number of path segments.Query parameters – Named parameters in the query string fill keyword arguments when path parameters are exhausted. For example,
/greet?name=Alicealso passes"Alice"to thenameparameter.Body/form data – For POST, PUT and PATCH requests, form fields populate handler arguments. JSON bodies are decoded into a dictionary of key/value pairs.
Files – If the request is multipart/form‑data, uploaded files appear in
files. You can declare a file argument in your handler signature to receive a file object.Session data – Values stored in
sessionfill remaining parameters. See Managing sessions for details.Default values – If no other source provides a value, default values in your function signature are used.
If MicroPie cannot determine a value for a required parameter, it
returns a 400 Bad Request.
Choosing an input access style¶
MicroPie gives you three levels of request input access. Prefer the simplest level that fits the handler.
Handler arguments are the most concise option. Use them when an endpoint needs a small number of named values and the normal binding order is acceptable.
class MyApp(App): async def search(self, q="", page="1"): return {"q": q, "page": int(page)}
This works for
/search?q=micropie&page=2without touchingself.requestdirectly.Helper methods are best when the handler needs explicit control over where a value comes from, a default value, or the full JSON payload.
class MyApp(App): async def search(self): q = self.request.query("q", "") page = int(self.request.query("page", "1")) return {"q": q, "page": page} async def submit(self): username = self.request.form("username", "Anonymous") return {"submitted_by": username} async def api_submit(self): payload = self.request.json() username = self.request.json("username", "Anonymous") return {"submitted_by": username, "raw": payload}
The helper methods are:
self.request.query(name, default=None): first query-string value forname.self.request.form(name, default=None): first parsed body value fornamefrom form data, or from a top-level JSON object mirrored into body parameters.self.request.json(name=None, default=None): full parsed JSON payload when called with no name, or one top-level JSON object value whennameis provided.
Raw attributes are useful when you need the lower-level parsed structures, such as repeated query parameters, all submitted form values, uploaded files, or middleware decisions.
self.request.path_params: list of positional path segments.self.request.query_params:dict[str, list[str]]parsed from the query string.self.request.body_params:dict[str, list[str]]parsed from form-urlencoded payloads, multipart text fields, or mirrored from top-level JSON objects.self.request.session: session dictionary.self.request.files: uploaded multipart files.self.request.headers: lower-case request header mapping.
For example, use
query_paramswhen repeated values matter:class MyApp(App): async def filter(self): tags = self.request.query_params.get("tag", []) return {"tags": tags}
Do not await request helpers¶
The request helper methods are synchronous accessors over data MicroPie
has already parsed for the current request. Do not use await with
query(), form() or json():
class MyApp(App):
async def submit(self):
data = self.request.json()
username = self.request.form("username", "")
q = self.request.query("q", "")
return {"data": data, "username": username, "q": q}
For JSON and URL-encoded form requests, the body has been read before
your handler runs. Multipart file uploads are the main exception:
uploaded file content is exposed as an asyncio.Queue in
self.request.files and should be read asynchronously.
Examples¶
The following examples illustrate common patterns:
class MyApp(App):
async def greet(self, name="Guest"):
"""Return a greeting for a named visitor.
If the ``name`` argument is not provided via the path or
query parameters, ``"Guest"`` is used as a default.
"""
return f"Hello, {name}!"
async def add(self, x, y):
"""Add two numbers provided via path segments.
Example: ``/add/2/3`` returns ``5``.
"""
return str(int(x) + int(y))
async def submit(self, username="Anonymous"):
"""Handle a form submission.
This handler accepts POST requests and uses the
``username`` field from the request body.
"""
return f"Form submitted by: {username}"
See Request objects for the attributes
available on the current request and App class for
details about the App class.
HTTP methods and responses¶
Handlers run for any HTTP method unless you explicitly check
self.request.method inside the handler. It is your
responsibility to dispatch based on the method if your endpoint should
behave differently for GET and POST. Handlers may return:
A string or bytes – sent as the body of the response with a
200 OKstatus.A JSON‑serialisable object – automatically encoded into JSON and returned with a
Content‑Typeofapplication/json.A tuple
(status_code, body)– sets the HTTP status and body.A tuple
(status_code, body, headers)– sets status, body and additional headers. Headers should be a list of(name, value)pairs.A generator or async generator – streams chunks to the client. Use this for large responses or server‑sent events.
Advanced routing¶
You can implement explicit routing, path prefixing or complex
dispatching by writing a custom HttpMiddleware. See
the Writing middleware guide and the examples in the
examples/explicit_routing directory of the source distribution.