What is Vesta?

Vesta turns a plain Python class into an HTTP server. You decorate methods with @Server.expose and they become routes. Query parameters are injected directly as keyword arguments. No URL patterns to write, no request objects to parse.

from vesta import Server

class App(Server):
    @Server.expose
    def index(self):
        return "<h1>Hello!</h1>"

    @Server.expose
    def api_greet(self, name="World"):
        return f"Hello, {name}!"

App(path=__file__, configFile="/server.ini")

A GET to /api_greet?name=Alice returns Hello, Alice!. That's the whole routing model.

Features

🔀

Routing

Decorator-based routes. Method names become URL paths. Parameters auto-injected.

🗄️

Query Builder

PostgreSQL ORM with simple dict-based CRUD and a filter chain for complex queries.

🔐

UniAuth

Shared authentication database with JWT, bcrypt, email verification and password reset.

📨

Mailing

SMTP + DKIM email sending with HTML templates.

WebSockets

Real-time bidirectional messaging with an authenticated client pool.

🎨

JS Framework

Frontend library for XHR, reactive state, navigation, templating and i18n.

🛠️

CLI

vesta init scaffolds a project. Commands for DB, Nginx and systemd setup.

🔒

Secure defaults

HttpOnly cookies, SameSite=Strict, DKIM, bcrypt, path traversal protection.

Installation

pip install vesta-web

Server types

Choose the right base class for your project:

ClassWhen to useIncludes
BaseServer Static sites, simple APIs Routing, file serving, cookies
Server Full-stack apps with users Everything above + DB, UniAuth, Mailing
Note WebSockets are opt-in via features = {"websockets": True} regardless of which base class you use.

Architecture overview

A Vesta app is a single Python file. The App class inherits from Server (or BaseServer), declares its routes as methods, and calls itself at the bottom to start the server.

from vesta import Server, HTTPError, HTTPRedirect
from os.path import abspath, dirname
import json

PATH = dirname(abspath(__file__))

class App(Server):
    features = {
        "errors": {404: "/static/404.html"}
    }

    @Server.expose
    def index(self):
        return self.file(PATH + "/static/index.html")

    @Server.expose
    def api_posts(self):
        self.response.type = "json"
        posts = self.db.getAll("posts", None, selector="id")
        return json.dumps(posts)

App(path=PATH, configFile="/server.ini")

Next steps