patx/micropie
improve json request and response handling
Commit 5dc0b4f · patx · 2025-02-20T17:23:42-05:00
Comments
No comments yet.
Diff
diff --git a/MicroPie.py b/MicroPie.py
index 936b34d..3402981 100644
--- a/MicroPie.py
+++ b/MicroPie.py
@@ -148,6 +148,7 @@ class Request:
self.path_params: List[str] = []
self.query_params: Dict[str, List[str]] = {}
self.body_params: Dict[str, List[str]] = {}
+ self.get_json: Any = {}
self.session: Dict[str, Any] = {}
self.files: Dict[str, Any] = {}
@@ -202,7 +203,7 @@ class App:
if scope["type"] == "http":
await self._asgi_app_http(scope, receive, send)
else:
- pass # Handle websockets and more in the future.
+ pass # Handle websockets, lifespan and more in the future.
async def _asgi_app_http(
self,
@@ -275,8 +276,6 @@ class App:
request.session = {}
# Parse body parameters.
- request.body_params = {}
- request.files = {}
if method in ("POST", "PUT", "PATCH"):
body_data = bytearray()
while True:
@@ -290,12 +289,9 @@ class App:
if "application/json" in content_type:
try:
json_body = json.loads(body_data.decode("utf-8"))
- # In case JSON is an object, convert key/value pairs to lists for consistency
+ request.get_json = json_body
if isinstance(json_body, dict):
request.body_params = {k: [str(v)] for k, v in json_body.items()}
- else:
- # For other JSON types, e.g., arrays, store under a single key
- request.body_params = {"data": [str(json_body)]}
except Exception as e:
status_code = 400
response_body = "400 Bad Request: Invalid JSON"
@@ -364,6 +360,7 @@ class App:
await self._send_response(send, status_code, response_body)
return
+ # Handle responses
if isinstance(result, tuple):
if len(result) == 2:
status_code, response_body = result
@@ -378,7 +375,8 @@ class App:
# If result is not a tuple, treat it as body only
response_body = result
- if isinstance(response_body, dict):
+ # Detect JSON responses
+ if isinstance(response_body, (dict, list)):
response_body = json.dumps(response_body)
extra_headers.append(
("Content-Type", "application/json")
diff --git a/README.md b/README.md
index a411177..e5bfd8d 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ pip install micropie[all]
This will install MicroPie along with `jinja2` for template rendering and `multipart`/`aiofiles` for parsing multipart form data.
### **Minimal Setup**
-You can also install MicroPie without dependencies via pip:
+You can also install MicroPie without ANY dependencies via pip:
```bash
pip install micropie
```
@@ -102,7 +102,8 @@ class MyApp(App):
return f"Submitted by: {username}"
```
-By default, MicroPie's route handlers can accept any request method, it's up to you how to handle any incoming requests! You can check the request method (and an number of other things specific to the current request state) in the handler with`self.request.method`.
+By default, MicroPie's route handlers can accept any request method, it's up to you how to handle any incoming requests! You can check the request method (and an number of other things specific to the current request state) in the handler with`self.request.method`. You can see how to handle POST JSON data at [examples/api](https://github.com/patx/micropie/tree/main/examples/api).
+
### **3. Real-Time Communication with Socket.IO**
Because of its designed simplicity, MicroPie does not handle WebSockets out of the box. While the underlying ASGI interface can theoretically handle WebSocket connections, MicroPie’s routing and request-handling logic is designed primarily for HTTP. While MicroPie does not natively support WebSockets, you can easily integrate dedicated Websockets libraries like **Socket.IO** alongside Uvicorn to handle real-time, bidirectional communication. Check out [examples/socketio](https://github.com/patx/micropie/tree/main/examples/socketio) to see this in action.
@@ -197,7 +198,7 @@ The best way to get an idea of how MicroPie works is to see it in action! Check
- File uploads
- Serving static content with ServeStatic
- Session usage
-- Sessions
+- JSON Requests and Responses
- Websockets with Socket.io
- Async Streaming
- Middleware
@@ -302,6 +303,7 @@ Represents an HTTP request in the MicroPie framework.
- `path_params`: List of path parameters.
- `query_params`: Dictionary of query parameters.
- `body_params`: Dictionary of body parameters.
+- `get_json`: JSON request body object.
- `session`: Dictionary of session data.
- `files`: Dictionary of uploaded files.
@@ -351,7 +353,7 @@ The `App` class is the main entry point for creating MicroPie applications. It i
Handlers can return responses in the following formats:
-1. String or bytes or JSON (`dict`)
+1. String or bytes or JSON
2. Tuple of (status_code, body)
3. Tuple of (status_code, body, headers)
4. Async or sync generator for streaming responses
diff --git a/examples/api/simple.py b/examples/api/simple.py
index 1f3211e..ea2b9f9 100644
--- a/examples/api/simple.py
+++ b/examples/api/simple.py
@@ -3,8 +3,18 @@ from MicroPie import App
class Root(App):
- async def index(self, id, name, age, zip):
+ async def index(self, id, name, age):
if self.request.method == 'POST':
- return {'id': id,'name': name,'age': age,'zip': zip}
+ return {'id': id,'name': name,'age': age}
+
+ async def echo(self):
+ data = self.request.get_json
+ return {"input": data, "extra": True}
+
+ async def example(self):
+ return ["a", "b"]
+
+ async def html(self):
+ return 'Hello world'
app = Root()
diff --git a/pyproject.toml b/pyproject.toml
index e12b62f..a20e9bc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
[project]
name = "MicroPie"
-version = "0.9.9.4"
+version = "0.9.9.5"
description = "An ultra micro ASGI web framework"
keywords = ["micropie", "asgi", "microframework", "http"]
readme = "README.md"