Metadata-Version: 2.4
Name: classapi
Version: 0.1.0
Summary: Add your description here
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: fastapi[standard]>=0.129.0

# ClassApi
ClassApi is a small convenience layer on top of FastAPI that enables class-based views (CBV). It preserves FastAPI's features (typing, dependencies, automatic docs) while letting you organize handlers as classes.

**Key features**
- Use `BaseView` as a base class for handlers (`get`, `post`, `put`, ...).
- Support for `pre_process` and `pre_<method>` hooks to validate or transform requests.
- Register route modules by module path (supports relative module paths like `.src.urls`).
- Combined signatures from `pre_process` and the handler method are exposed to FastAPI for documentation and form generation.

**Development setup (using `uv` helper)**
1. Create a virtual environment:
```bash
python -m venv .venv
```
2. Use your `uv` helper to run `pip` inside the project environment and install dependencies:
```bash
uv run pip install fastapi uvicorn
# or install from requirements: uv run pip install -r requirements.txt
```

**Quickstart**
Create `main.py`:
```py
from classapi import ClassApi

app = ClassApi()

app.include_routers(".src.urls")
```

Example routes and views layout (tests/app_test/src):
```py
# tests/app_test/src/urls.py
from .views import HelloWorldView

urls = [
	{"path": "/hello", "view": HelloWorldView}
]

# tests/app_test/src/views.py
from classapi import View, Header, HTTPException
from typing import Annotated

class ValidateUser(BaseView):
	def pre_process(self, jwt: Annotated[str | None, Header()] = None):
		if jwt != "valid_jwt":
			raise HTTPException(status_code=401, detail="Unauthorized")

class HelloWorldView(ValidateUser, BaseView):
	methods = ["GET"]

	def get(self, name: str = "World"):
		return {"Hello": name}
```

**Supported `urls` formats**
- Dict entries: `{"path": "/x", "view": MyView, ...fastapi kwargs...}` — extra kwargs (e.g. `response_model`) are forwarded to `add_api_route`.
- Tuple/list entries: `("/x", MyView)`.
- You may use relative imports from the calling module: `app.include_routers(".src.urls")`.

**`View` classes**
- Define HTTP methods: `get`, `post`, `put`, `delete`, `patch`.
- Limit exposed methods with `methods = ["GET"]` on the class.
- Hooks:
  - `pre_process(self, ...)` — runs before any handler.
  - `pre_get(self, ...)`, `pre_post(...)`, ... — run before a specific handler.
- Signatures from `pre_process`, `pre_<method>` and the handler itself are merged and exposed to FastAPI; annotate parameters with `Annotated[..., Header()]`, `Cookie()`, etc., to appear correctly in `/docs`.

Example: header extraction in `pre_process`:
```py
def pre_process(self, jwt: Annotated[str|None, Header()] = None):
	...
```

If you accidentally place `Annotated[...]` as a default (e.g. `jwt = Annotated[...]`), ClassApi attempts to normalize it so FastAPI recognizes the dependency. Still, annotate parameters properly when possible.

**Running the app**
- Use `uv` to run the app with reload during development:
```bash
uv run uvicorn tests.app_test.main:app --reload
```
or, if you use the helper script `test_init.py` at the repository root:
```bash
uv run .\test_init.py
```

**Debugging endpoint signatures**
If docs don't show expected parameters, you can inspect endpoint signatures at runtime:
```py
for r in app.routes:
	print(r.path, getattr(r.endpoint, '__signature__', None))
```

**Editor integration (VSCode / Pylance)**
Pylance is a static analyzer and doesn't pick up runtime-generated signatures. To get editor hovers that match your runtime docs, create a `.pyi` stub next to your views module describing the public signatures (this does not change runtime behavior).

**Contributing**
- Open issues or PRs.
- Add tests under `tests/` and run them with `pytest`.

---
If you want, I can generate a `views.pyi` stub for your views, add example tests, or add a minimal `pyproject.toml`. Which should I do next?
