Reference

Routes

Define routes by writing an async function and slapping a decorator on top of it.

You can use the 4 standards HTTP methods: GET, POST, PUT and DELETE.

            
@rd.get("/users")
async def get_users(request):
    return rd.html(...)

@rd.post("/new_user")
async def new_user(request):
    return rd.html(...)

@rd.put("/rename_user")
async def rename_user(request):
    return rd.html(...)

@rd.delete("/remove_user")
async def remove_user(request):
    return rd.html(...)
            

You can also use parameters in your routes and get back these values in your handler (see the "Requests" chapter)

Requests

Request is the only stateful object in Red Dwarf.

When Red Dwarf receives a request, it parses it for you into a Request object that you can freely access.

Note: All the attributes are strings or dicts.

            
@rd.get("/docs/<folder_id>/<document_id>")
async def serve_document(request):
    print(request.method)
    # 'GET'
    print(request.raw_path)
    # '/docs/folder18/document4?page=42'
    print(request.path)
    # '/docs/folder18/document4'
    print(request.params)
    # {'folder_id': 'folder18', 'document_id': 'document4'}
    print(request.query)
    # {'page': ['42']}
    print(request.headers)
    # {'host': '...', ...}
    print(request.body)
    # b''
    print(request.cookies)
    # {'user_id': ...}
    print(request.signals)
    # {'theme': 'light'}
    return rd.html(...)
            

As you see, Datastar signals are automatically parsed.

Responses

In Red Dwarf, there are only 4 possible responses.

Most of the time, you'll answer with rd.html().

            
@rd.get("/")
async def home(request):
    return rd.html(<h1>Hello World!</h1>)

@rd.get("/red")
async def red(request):
    headers = ["X-Accel-Buffering: No"]
    user_id = "123"
    return rd.html(
        <h1>Hello World!</h1>
        headers=headers,
        cookies={'user_id': user_id}
    )
            

You can also use rd.empty() to return an empty response (useful in CQRS patterns).

            
@rd.get("/v1")
async def old_version(request):
    return rd.redirect("/v2")

@rd.post("/command")
async def handle_command(request):
    user_id = request.cookies.get("user_id")
    if user_id:
        database.process(user_id)
    return rd.empty()
            

Finally, you can use rd.patch() to any Datastar request.

            
@rd.get("/sse")
async def sse_stream(request):
    async for message in pubsub_channel():
        yield rd.patch(f"<div id='message'>{message}</div>")
            

The HTML in rd.patch() will replace the one on the page. Magic!

App

That's all!

You now know how to use Red Dwarf.

The last thing you need to do is launch your app

            
if __name__ == "__main__":
    rd.run(reload=True)
            

You're good to go!

By default, Red Dwarf will serve on localhost.

You can also specify a custom host adress, or use a Unix port if you prefer.

Note: During development, you can use reload=True. It will detect any change in Python files or in your static folder, and will relaunch the server.

            
if __name__ == "__main__":
    rd.run(sock="/unix.sock", reload=True)
            

Before you go

One last thing.

Red Dwarf gives you useful before_request / after_response decorators.

It's... pretty straightforward.

Note: With before_request, you can return early.

            
@rd.before_request
def cookie_check(request):
    if not request.get("user_id"):
        return rd.redirect("/")

@rd.after_response
def log(request):
    logger.info("Another successful response on f{request.path}!")
            

Off you go!

You can continue by reading the FAQ, the Cookbook or the Essays (links)

Go build something!