Restrict access

A how-to guide: turn callers away outside opening hours, by answering instead of building the page they asked for.

from collections.abc import Callable
from datetime import datetime

from sextile import CallNext, Page, PageRequest, PageRouter, Sextile, notice_page

router = PageRouter()


@router.page("1", name="index", title="Booking office")
async def index(request: PageRequest) -> Page:
    return notice_page(request, "Key a service number.")


def open_between(first: int, last: int, *, now: Callable[[], datetime]) -> CallNext:
    async def hours(request: PageRequest, call_next: CallNext) -> Page | None:
        if first <= now().hour < last:
            return await call_next(request)
        return notice_page(
            request,
            "The booking office is closed.",
            "",
            f"Please call between {first:02d}:00 and {last:02d}:00.",
            title="CLOSED",
            home=None,
        )

    return hours


app = Sextile(
    name="Booking",
    pages=[*router],
    middleware=[open_between(8, 20, now=lambda: datetime(2026, 8, 19, 23, 0))],
)

frame = fetch(app, "1")
 CLOSED                               1a
  
The booking office is closed.           
                                        
Please call between 08:00 and 20:00.    
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
  
                                        

A middleware that returns a Page without calling call_next answers instead of the handler, so every page it guards shows this frame and no page is built behind it. It is outermost in middleware=[...], so it decides before any inner middleware or the page runs. Restrict some pages and not others by testing request.address before you refuse, and take the caller’s identity from request.session, which lasts exactly as long as their line — Remember a caller keeps state there.

Why the framework offers no sign-in of its own: who may reach a page is the service’s policy, and the chain gives it the place to enforce one. The moves and the order are in Middleware; wording a notice is Customise the not-found and failed notices.