Docs

Routes

A route is code you run when a user requests an URL.

Define routes with an async function + a decorator.

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

@rd.post("/new_user")
async def new_user(request):
    return rd.html(...)
    
Advanced: Other methods PUT - @rd.put() - for idempotent modifications
DELETE - @rd.delete() - for deletions

Requests

User requests can contain useful information.

There are two ways to retrieve them:

Method 1: The information is in the URL

For example, the user wants page 67 of book 42. Make them click on a link like this: "www.site.com/books/42?page=67" and retrieve this data like this:

    
@rd.get("/books/<book_id>")
async def serve_book(request):
    print(request.params)
    # {'book_id': '42'}
    print(request.query)
    # {'page': ['67']}
    
Method 2: The information is in the Request

This happens either when you stored the information beforehand with cookies, or when you used Datastar's data-bind method to link a value with an input.

    
@rd.post("/submit_form")
async def process_form(request):
    print(request.cookies)
    # {'session_id': ...}
    print(request.signals)
    # {'username': 'red'}
    
Advanced: Other data stored in request Here is the rest of the data stored in request:
Advanced: Running code before requests To run code before processing requests, use the @before_request decorator.
A common use case is to "reject" requests that don't have a security token:
        
@before_request
def check_token(request):
    if not request.cookies.get("secret_key"):
        return rd.redirect("/")
        

Use sync functions under this decorator.

An early return will cancel request processing.

Responses

The way you respond to a user's request depends on the type of the request.

Case 1: Normal request

(For example, when a user access a URL from the status bar, or after clicking on a link.)

Simply use rd.html():

    
@rd.get("/")
async def home(request):
    return rd.html(<h1>Hello World!</h1>)
    
Advanced: Setting cookies and headers You can pass a list of headers or a dict of cookies as additional parameters.
        
@rd.get("/")
async def home(request):
    headers = ["X-Accel-Buffering: No"]
    cookies = {'user_id': "123"}
    return rd.html(
    <h1>Hello World!</h1>
    headers=headers,
    cookies=cookies
    )
    
Case 2: Datastar request

If the request was triggered by a Datastar action, you can modify an element on the page.

    
@rd.get("/update")
async def update(request):
    return rd.html("<main>...</main>")
    
Advanced: Patching multiple elements You can patch multiple elements using rd.patch().
Note that you have to yield the values.
        
@rd.get("/process")
async def process_user_request(request):
    yield rd.patch("<main>Processing...</main>")
    result = compute_stuff()
    yield rd.patch(f"<main>Result is {result}</main>")
        
Advanced: Empty responses (CQRS pattern) A very useful pattern in Datastar is to have one long-lived response with other "command" endpoints.
The long-lived response will yield through a pubsub-activated generator and the command endpoints will return empty responses.
        
@rd.get("/read")
async def read_stream(request):
    async for message in pubsub.listen():
        yield rd.patch(f"<div id='message'>{message}</div>")
    
        
@rd.post("/command")
async def handle_command(request):
    user_id = request.cookies.get("user_id")
    value = process(user_id)
    pubsub.send(value)
    return rd.empty()
	
Advanced: Redirection

You may redirect users if resources moved with rd.redirect():

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

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()
    
Advanced: Reload mode You can use reload=True. It will detect any change in your Python files or in your static folder, and will relaunch the server.
Useful for prototyping, don't use it in production.
        
if __name__ == "__main__":
    rd.run(reload=True)
        
Advanced: Serving on a different port
        
if __name__ == "__main__":
    rd.run(port="123.4.5.6:7890")
        
Advanced: Serving on a Unix socket
        
if __name__ == "__main__":
    rd.run(sock="/unix.sock")
        

Off you go!

Go build something cool!

You can continue by studying the Examples, checking the FAQ, or reading the Essays.

Have fun!