Skip to content

1363V4/red-dwarf

Repository files navigation

Red Dwarf User Manual

logo

Marketing

  1. Declare routes
  2. Send Html
  3. ...
  4. Profit!

Overview

What is Red Dwarf?

Red Dwarf is a very minimal and very opinionated Python ASGI server.

Red Dwarf:

  • only use the Python default library
  • is fast?
  • has sensible helper functions / looks familiar
  • is decently secure?
  • gets you running in seconds

Why Red Dwarf?

First, Red Dwarf highly recommends Datastar.

Datastar's philosophy (and Red Dwarf's) is "keeping state in the backend".

But the "backend" is not equal to the "server", it's more than that. It's your database, your cronjobs, your pubsub system, your other Python scripts...

Red Dwarf gets out of your way by doing what a server should do (receiving and responding to Web requests) and nothing more, so you can write your Python however you see fit.

How to use Red Dwarf?

Simply run uv add red-dwarf to your project to get going.

Note: You need Python minimum version ????????????????????? hmm yes if you have to import zlib/compress which are optional modules but even there with asyncio, let's say 3.11

Then, head over to Quickstart

When not to use Red Dwarf?

Red Dwarf is intended as a first "entry point" into the world of Datastar.

Don't use Red Dwarf if:

  • you need multiple workers
  • you need middlewares
  • you need telemetry
  • you need advanced server functions
  • you're doing anything serious

We instead recommend the following tools:

Quickstart

Hello World

After installing uv add red-dwarf, create a new file named app.py and write:

from red_dwarf import App, Input, Output

app = App()

@app.get("/")
def index(i,o):
	return o.html("<h1>hello world!</h1>")

if __name__ == "__main__":
	app.run()

Open a web browser and go to http://localhost:8080/: you should see the hello world message.

What we did here:

  • Created our server with app = App()
  • Registered a handler index for GET request on the home page @app.get("/")
  • Told the handler to output HTML
  • Started the server with app.run()

Your first app

Let's modify app.py:

from red_dwarf import App, Input, Output

app = App()

@app.get("/")
def index(i,o):
	return o.html(
'''
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link rel="stylesheet" href="/static/css/index.css"/>
    <script type="module" src="/static/js/datastar.js">
</head>
<body class="gc">
...
</body>
</html>
'''
    )

if __name__ == "__main__":
	app.run()

We now have a proper HTML "file" (well, a string) which now includes Datastar and gold.css.

You'll notice immediately that the page is reactive. Go to localhost and fill the input: the text is updated on the frontend by Datastar.

Next, we'll add a route to react from the backend. Start by modifying the index HTML to:

...

then add route "dwarf_name" like this:

...

Tada!

Your first stream

Finally, let's see how alive and patch work by opening a SSE stream.

We start from our previous code:

...

And we modify the body to open a SSE stream:

...

Now we just need to add the SSE route:

...

Go to localhost and watch the dwarf count time!

NB: we only allow patching html with datastar default merge strategy that should work 100% of the time patch signals by piggybacking them on whatever (put that shit in details)

Usage behing a reverse proxy

we like caddy

NB: for nginx you have to disable X-Accel-Buffering in the headers for sse streams

The rest of the backend

Database

We like SQLITE and TINYDB

Pubsub

We like REDIS and NATS

HTML generation

We like what Stario and are waiting for t-strings

Telemetry

We like LOGGER

BG tasks

We like ASYNCIO but are waiting for free threading

FAQ

Question?

Answer.

Can I use sync functions?

No. Everything in RD is async by default.

Can I respond with json?

No.

Is there type matching on regex routes?

No, they're strings.

How can I debug?

We recommend using print().

How can I test?

We recommend using assert.

What?! You didn't write any tests

Not yet, no.

Can I add routes at runtime?

Well you can change your code and the server will restart, but... why do that?

Why is there no compression?

We let the reverse proxy do it. because caddy will compress it faster, after its own middlewares and can also use precompressed files!! to save some cpu (rarely the bottleneck tbh but hey) yeah you lose some on the compression window

Why is there no static files?

We let the reverse proxy do it, and the browser cache them with etags.

But why?

Just like everybody needs a frontend framework (like Datastar), everybody needs a reverse proxy. So more people work on them, which means they're likely better.

We do the absolute minimum at the Python level and let Caddy's Go code and Chrome's C++ do the heavy lifting.

What status code can I send?

200 for html. and the rest is classic.

How can I set cookies?

Very easy, request.cookies.get html(cookie={'key': value})

How do I add headers

headers=["Wait: What"] there's no reason to do it, so if you do it please be prepared

How to serve static templates

Just load them into memory!

Use a real framework

I prefer starlette for actually reading the code.

About

WIP - work in Python

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors