myfy web routing with FastAPI-like decorators. Use when working with WebModule, @route decorators, path parameters, query parameters, request bodies, AuthModule for authentication, RateLimitModule for rate limiting, or error handling.
myfy provides FastAPI-like routing with full DI integration.
from myfy.web import route
@route.get("/path")
async def handler() -> dict:
return {"message": "hello"}
@route.post("/path", status_code=201)
async def create() -> dict:
return {"created": True}
@route.put("/path/{id}")
async def update(id: int) -> dict:
return {"updated": id}
@route.delete("/path/{id}", status_code=204)
async def delete(id: int) -> None:
pass
@route.patch("/path/{id}")
async def partial_update(id: int) -> dict:
return {"patched": id}
Extract from URL template using {param}:
@route.get("/users/{user_id}/posts/{post_id}")
async def get_post(user_id: int, post_id: int) -> dict:
return {"user": user_id, "post": post_id}
Path parameters are:
Use Query for explicit query parameters:
from myfy.web import Query
@route.get("/search")
async def search(
q: str = Query(default=""), # With default value
limit: int = Query(default=10), # Integer query param
page: int = Query(alias="p"), # Aliased (?p=1 in URL)
) -> dict:
return {"query": q, "limit": limit, "page": page}
Use Pydantic models or dataclasses for request bodies:
from pydantic import BaseModel
class UserCreate(BaseModel):
email: str
name: str
@route.post("/users", status_code=201)
async def create_user(body: UserCreate, session: AsyncSession) -> dict:
user = User(**body.model_dump())
session.add(user)
await session.commit()
return {"id": user.id}
Request bodies are automatically:
Parameters are classified in this order:
{param} in route pathQuery(...)@route.post("/users/{user_id}/orders")
async def create_order(
user_id: int, # 1. Path param (matches {user_id})
limit: int = Query(default=10), # 2. Query param (explicit Query)
body: OrderCreate, # 3. Request body (Pydantic model)
session: AsyncSession, # 4. DI dependency
settings: AppSettings, # 4. DI dependency
) -> dict:
...
Use Authenticated for protected routes:
from myfy.web import Authenticated, AuthModule
from dataclasses import dataclass
@dataclass
class User(Authenticated):
email: str
# Register auth provider
def my_auth(request: Request) -> User | None:
token = request.headers.get("Authorization")
if not token:
return None # Results in 401
return User(id="123", email="user@example.com")
app.add_module(AuthModule(authenticated_provider=my_auth))
# Protected route - returns 401 if not authenticated
@route.get("/profile")
async def profile(user: User) -> dict:
return {"id": user.id, "email": user.email}
from myfy.web import abort
@route.get("/users/{user_id}")
async def get_user(user_id: int, session: AsyncSession) -> dict:
user = await session.get(User, user_id)
if not user:
abort(404, "User not found")
return {"user": user}
from myfy.web import errors
raise errors.NotFound("User not found")
raise errors.BadRequest("Invalid email", field="email")
raise errors.Unauthorized("Invalid token")
raise errors.Forbidden("Access denied")
raise errors.Conflict("Email already exists")
from myfy.web.exceptions import WebError
class RateLimitExceeded(WebError):
status_code = 429
error_type = "rate_limit_exceeded"
from myfy.web.ratelimit import RateLimitModule, rate_limit, RateLimitKey
# Add module
app.add_module(RateLimitModule())
# Rate limit by IP (default)
@route.get("/api/data")
@rate_limit(100) # 100 requests per minute per IP
async def get_data() -> dict:
...
# Rate limit by authenticated user
@route.get("/api/profile")
@rate_limit(50, key=RateLimitKey.USER)
async def get_profile(user: User) -> dict:
...
Routes can return:
# Dict (serialized to JSON)
@route.get("/json")
async def json_response() -> dict:
return {"key": "value"}
# Pydantic model (serialized to JSON)
@route.get("/model")
async def model_response() -> UserResponse:
return UserResponse(id=1, name="John")
# None for 204 No Content
@route.delete("/users/{id}", status_code=204)
async def delete_user(id: int) -> None:
...
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer