- What Even Is This
- Installation: Your First Mistake
- Hello, World, You Minimalist Freak
- Routing: Guess the URL by Reading a Method Name
- Parameters: MicroPie Sees All
- Sessions: For When You Need to Remember Your Regret
- Templates: Jinja2 or Bust
- WebSockets: Talk to Me, You Coward
- Middleware: I See You, Judge You, Modify You
- Streaming Responses: Because Why Not
- Lifespan Hooks: Do Stuff on Startup Because You Forgot to Earlier
- Benchmark: MicroPie vs The Bloated Corpses
MicroPie is an ASGI framework.
It’s like FastAPI, but faster, smaller, and it doesn’t constantly ask you for your BaseModel.
It routes based on method names. It handles files bigger than your dreams. It’s got WebSockets and streaming.
And it still fits inside one file if you really want it to.
pip install micropie[all]That gives you:
jinja2for making HTML that's slightly more complex than "Hello"orjsonso you can tell people your API is “fast”multipartso you can upload your cat videos in 40GB chunksuvicornso it actually runs
You can also install it like this:
curl -O https://raw.githubusercontent.com/patx/micropie/main/micropie.pyBoom. Framework installed. Meanwhile, Django’s install guide is still printing.
from micropie import App
class MyApp(App):
async def index(self):
return "Hi. It's me. Your handler."
app = MyApp()Run it with:
uvicorn app:appYes. That’s it. No decorators. No router. Just one async method and a dream.
class AppOfMystery(App):
async def greet(self, name):
return f"Hello {name}. You're in /greet/{name}"
async def scream(self):
return "AAAAAAAAAAAAAAAAAAA"MicroPie just knows:
/greet/Bob→greet(self, name="Bob")/scream→scream()/→index(), if it exists
If your method starts with _, it's private. Like _please_dont_call_this.
MicroPie fills your method args with whatever it can find:
- Path parameters
- Query strings
- Form data
- Raw POST JSON
- Cookies
- Your browser history (probably)
async def info(self, name="Ghost", age="???"):
return f"{name} is {age} years old. Allegedly."class RememberMe(App):
async def index(self):
visits = self.request.session.get("visits", 0)
self.request.session["visits"] = visits + 1
return f"Visit #{visits + 1}. Still here?"Yes, it handles sessions with cookies. You can also plug in your own backend if you’re that guy.
class Web2(App):
async def index(self):
return await self._render_template("index.html", title="Hello", message="World")And in templates/index.html:
<h1>{{ title }}</h1>
<p>{{ message }}</p>MicroPie doesn’t care what CSS framework you’re using. Neither should you.
class TalkToMe(App):
async def ws_chat(self, ws):
await ws.accept()
while True:
msg = await ws.receive_text()
await ws.send_text(f"You said: {msg}")MicroPie handles:
ws://localhost:8000/chat→ws_chat(self, ws)ws.accept(),ws.send_text(), etc.- You forgetting to close the socket
from micropie import HttpMiddleware
class Judge(HttpMiddleware):
async def before_request(self, request):
print(f"Look who's hitting {request.path}... again.")
async def after_request(self, request, status, body, headers):
print("You got a response. For now.")
app = MyApp()
app.middlewares.append(Judge())Add logging, auth, CSRF, existential doubt—whatever.
async def drip_feed(self):
async def gen():
for i in range(5):
yield f"Chunk {i}\n"
return gen()Yes, you can yield chunks over time. No, you still don’t need a response class.
async def wake_up():
print("Starting app...")
async def goodnight():
print("Shutting down...")
app.startup_handlers.append(wake_up)
app.shutdown_handlers.append(goodnight)Setup your DB. Close your DB. Cry a little. Whatever.
MicroPie is:
- For people who want performance and clarity
- For rebels who don’t need decorators
- For you, clearly, because you made it this far
So go forth. Build something ridiculous with MicroPie.