Haske is a modern Python web framework that combines the simplicity of Flask, the power of FastAPI, and the performance of Rust extensions. It is designed for developers who want to build fast, scalable, and maintainable web applications without unnecessary complexity.
- Introduction
- Installation
- Quickstart
- Routing
- Requests & Responses
- Middleware
- Sessions
- Templates
- ORM & Database
- Authentication
- CLI
- WebSockets
- Error Handling
- Testing
- Deployment
- Contributing
- License
Haske was built to solve a common problem in Python web development:
- Flask is simple, but too minimal for large apps.
- Django is powerful, but heavy and opinionated.
- FastAPI is fast, but focused mostly on APIs.
Haske combines the best of all worlds:
- π Simple API β inspired by Flask.
- β‘ Fast β powered by Rust extensions.
- π§ Flexible β lets you add only what you need.
- π Full-stack ready β supports templates, ORM, sessions, and WebSockets.
- Python 3.8+
- Rust (for building extensions)
- pip / virtualenv
pip install haskeOr, from source:
git clone https://github.com/Python-Katsina/haske-python.git
cd haske-python
python setup.pyCreate a file app.py:
from haske import Haske, Request, Response
app = Haske(__name__)
@app.route("/")
async def home(request: Request) -> Response:
return {"message": "Hello, Haske!"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, reload=True)Run the app:
python app.pyVisit: http://localhost:8000 π
Routing is how Haske connects URLs to functions.
@app.route("/hello")
async def say_hello(request: Request):
return {"message": "Hello World"}@app.route("/user/{username}")
async def greet_user(request: Request, username: str):
return {"message": f"Hello {username}"}@app.route("/search")
async def search(request: Request):
query = request.query.get("q", "none")
return {"search_for": query}@app.route("/submit", methods=["POST"])
async def submit(request: Request):
data = await request.json()
return {"received": data}Haske provides easy access to HTTP requests and responses.
@app.route("/headers")
async def headers(request: Request):
return {"user_agent": request.headers.get("User-Agent")}@app.route("/json")
async def json_response(request: Request):
return {"framework": "Haske", "type": "JSON"}from haske.responses import RedirectResponse
@app.route("/go")
async def go(request: Request):
return RedirectResponse(url="/hello")Middleware is code that runs before or after each request.
Uses include: logging, authentication, CORS, compression, etc.
from haske.middleware import Middleware
class LoggingMiddleware(Middleware):
async def before_request(self, request):
print(f"β‘οΈ Incoming request: {request.url}")
async def after_response(self, request, response):
print(f"β¬
οΈ Response status: {response.status_code}")
app.add_middleware(LoggingMiddleware)HTTP is stateless β it doesnβt remember users between requests.
Sessions allow you to store user data (like logins or cart items) across multiple requests.
- π Authentication (keep users logged in)
- π Shopping carts
- π Preferences & personalization
@app.route("/login", methods=["POST"])
async def login(request: Request):
data = await request.json()
username = data.get("username")
# Save to session
request.session["user"] = username
return {"message": f"Welcome {username}"}
@app.route("/profile")
async def profile(request: Request):
user = request.session.get("user")
if not user:
return {"error": "Not logged in"}
return {"profile": f"User profile for {user}"}Haske supports rendering HTML templates (Jinja2 or similar).
@app.route("/welcome")
async def welcome(request: Request):
return app.template("welcome.html", {"name": "Haske User"})templates/welcome.html:
<html>
<body>
<h1>Welcome {{ name }}!</h1>
</body>
</html>Haske can integrate with SQLAlchemy or other ORMs.
from haske.orm import Model, Column, Integer, String
class User(Model):
id = Column(Integer, primary_key=True)
name = Column(String)
# Create
new_user = User(name="Alice")
db.session.add(new_user)
db.session.commit()
# Query
user = User.query.filter_by(name="Alice").first()Authentication is usually built on top of sessions.
@app.route("/auth/login", methods=["POST"])
async def auth_login(request: Request):
data = await request.json()
if data["username"] == "admin" and data["password"] == "123":
request.session["user"] = "admin"
return {"status": "logged_in"}
return {"error": "Invalid credentials"}
@app.route("/auth/protected")
async def protected(request: Request):
if request.session.get("user") != "admin":
return {"error": "Unauthorized"}
return {"message": "Welcome, admin!"}Haske comes with a command-line interface.
haske new myprojecthaske runHaske supports real-time apps with WebSockets.
@app.websocket("/ws")
async def websocket_endpoint(socket):
await socket.send("Welcome to Haske Chat!")
async for message in socket:
await socket.send(f"You said: {message}")@app.exception_handler(404)
async def not_found(request: Request, exc):
return {"error": "Page not found"}Haske makes testing simple.
from haske.testing import TestClient
def test_homepage():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.json()["message"] == "Hello, Haske!"uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4gunicorn -k uvicorn.workers.UvicornWorker app:app- Fork the repo.
- Create a feature branch.
- Submit a pull request.
We welcome contributions in:
- Bug fixes
- New features
- Docs improvements
MIT License Β© 2025 Python Katsina Community