Skip to content

Instantly share code, notes, and snippets.

@patx
Created August 18, 2025 05:04
Show Gist options
  • Select an option

  • Save patx/23238bd27936a1e455864268985778b3 to your computer and use it in GitHub Desktop.

Select an option

Save patx/23238bd27936a1e455864268985778b3 to your computer and use it in GitHub Desktop.

🥝 The Officially Unofficial, Shamelessly Sarcastic Guide to MicroPie

Table of Contents:

  1. What Even Is This
  2. Installation: Your First Mistake
  3. Hello, World, You Minimalist Freak
  4. Routing: Guess the URL by Reading a Method Name
  5. Parameters: MicroPie Sees All
  6. Sessions: For When You Need to Remember Your Regret
  7. Templates: Jinja2 or Bust
  8. WebSockets: Talk to Me, You Coward
  9. Middleware: I See You, Judge You, Modify You
  10. Streaming Responses: Because Why Not
  11. Lifespan Hooks: Do Stuff on Startup Because You Forgot to Earlier
  12. Benchmark: MicroPie vs The Bloated Corpses

What Even Is This

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.

Installation: Your First Mistake

pip install micropie[all]

That gives you:

  • jinja2 for making HTML that's slightly more complex than "Hello"
  • orjson so you can tell people your API is “fast”
  • multipart so you can upload your cat videos in 40GB chunks
  • uvicorn so it actually runs

You can also install it like this:

curl -O https://raw.githubusercontent.com/patx/micropie/main/micropie.py

Boom. Framework installed. Meanwhile, Django’s install guide is still printing.

Hello, World, You Minimalist Freak

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:app

Yes. That’s it. No decorators. No router. Just one async method and a dream.

Routing: Guess the URL by Reading a Method Name

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/Bobgreet(self, name="Bob")
  • /screamscream()
  • /index(), if it exists

If your method starts with _, it's private. Like _please_dont_call_this.

Parameters: MicroPie Sees All

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."

Sessions: For When You Need to Remember Your Regret

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.

Templates: Jinja2 or Bust

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.

WebSockets: Talk to Me, You Coward

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/chatws_chat(self, ws)
  • ws.accept(), ws.send_text(), etc.
  • You forgetting to close the socket

Middleware: I See You, Judge You, Modify You

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.

Streaming Responses: Because Why Not

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.

Lifespan Hooks: Do Stuff on Startup Because You Forgot to Earlier

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.

Final Thoughts

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment