A modern, high-performance async web framework for building APIs from Python type hints, with automatic validation and interactive OpenAPI docs.
FastAPI uses standard type hints (via Pydantic) to declare request/response models, giving automatic parsing, validation, and self-generated Swagger/OpenAPI documentation. Built on Starlette and ASGI, it handles high-concurrency async workloads well. For security tooling it's an excellent choice for building well-documented internal APIs, C2-style task servers on infrastructure you control, and data-collection services that need robust input validation.
pip install "fastapi[standard]"Note
The [standard] extra includes the uvicorn ASGI server and the fastapi dev runner.
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI(title="Lab Findings API")
class Finding(BaseModel):
host: str
port: int = Field(ge=1, le=65535)
severity: str
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/findings", status_code=201)
def create_finding(finding: Finding):
return {"stored": finding.host, "port": finding.port}uvicorn main:app --host 127.0.0.1 --port 8000Type hints plus Pydantic models give request validation and an OpenAPI schema automatically — a malformed port is rejected with a 422 before your handler runs.
| API | Purpose |
|---|---|
FastAPI(title=, docs_url=) |
The application |
@app.get/post/put/delete(path) |
Route decorators |
BaseModel (Pydantic) |
Request and response schemas with validation |
Field(ge=, le=, max_length=) |
Field constraints |
response_model= |
Validate and filter the response |
Depends(callable) |
Dependency injection — auth, database sessions |
HTTPException(status_code, detail) |
Error responses |
status_code= |
Set the success status |
BackgroundTasks |
Work after the response is sent |
APIRouter() |
Split routes across modules |
TestClient(app) |
Test harness (from Starlette) |
/docs, /redoc, /openapi.json |
Auto-generated documentation |
FastAPI runs on an ASGI server — uvicorn in development, typically behind a reverse proxy in production.
A validated task/collection API:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="Recon API")
class CheckIn(BaseModel):
host: str
user: str
services: list[str] = []
@app.post("/checkin")
def checkin(data: CheckIn):
return {"received": data.host, "count": len(data.services)}
# Run with: uvicorn main:app --host 127.0.0.1 --port 8000$ curl -X POST 127.0.0.1:8000/checkin \
-H 'Content-Type: application/json' \
-d '{"host":"lab-01","user":"tester","services":["ssh","http"]}'
{"received":"lab-01","count":2}
Path/query parameters with automatic type validation:
from fastapi import FastAPI, HTTPException
app = FastAPI()
HOSTS = {"192.168.56.10": ["ssh", "http"]}
@app.get("/host/{ip}")
def host(ip: str, verbose: bool = False):
if ip not in HOSTS:
raise HTTPException(status_code=404, detail="unknown host")
result = {"ip": ip, "services": HOSTS[ip]}
if verbose:
result["count"] = len(HOSTS[ip])
return result$ curl "127.0.0.1:8000/host/192.168.56.10?verbose=true"
{"ip":"192.168.56.10","services":["ssh","http"],"count":2}
Bearer-token dependency to protect an endpoint:
from fastapi import FastAPI, Depends, HTTPException, Header
app = FastAPI()
def require_token(authorization: str = Header(default="")):
if authorization != "Bearer s3cr3t-lab-token":
raise HTTPException(status_code=401, detail="unauthorized")
@app.get("/tasks", dependencies=[Depends(require_token)])
def tasks():
return {"tasks": ["scan 192.168.56.0/24", "enum dns example.com"]}$ curl -H 'Authorization: Bearer s3cr3t-lab-token' 127.0.0.1:8000/tasks
{"tasks":["scan 192.168.56.0/24","enum dns example.com"]}
- Documented internal APIs — build tooling backends with automatic OpenAPI docs and strict input validation.
- Task / orchestration servers — coordinate agents and jobs on authorized red-team infrastructure you own.
- Data-collection services — accept structured check-ins/results with Pydantic models rejecting malformed input.
- Auth-protected endpoints — use dependencies to enforce token/API-key auth on sensitive routes.
- Rapid mock services — stand up realistic API targets for testing clients and integrations.
Warning
Deploy only on infrastructure you control. Bind to localhost or an authenticated interface, and require auth on any endpoint that returns sensitive data or triggers actions.
- Leaving
/docsand/openapi.jsonenabled on anything exposed — they publish your entire API surface. Setdocs_url=None, redoc_url=Nonewhere that matters. - Returning ORM objects directly without
response_model=, leaking fields such as password hashes. - Using
dictinstead of a Pydantic model, discarding the validation that is the main reason to use FastAPI. - Blocking calls in an
async defhandler — a synchronous database or network call stalls the event loop. Usedeffor blocking work, or an async client. - Permissive CORS —
allow_origins=["*"]with credentials enabled is a serious misconfiguration. - Binding to
0.0.0.0in a lab on an untrusted network. - Running
uvicorn --reloadoutside development.
[!warning] Authorized use only Run listeners only on hosts and networks you control. Bind to
127.0.0.1unless exposure is intended.
- Validation is the security feature. Pydantic rejects malformed input before it reaches your code — define constrained models rather than accepting free-form dictionaries.
response_modelprevents data leakage. Without it, a handler returning a database object can serialise hashes, tokens, and internal fields straight to the client.- The auto-generated docs are reconnaissance.
/docshands an attacker a complete map of every endpoint and schema. Disable them on anything reachable. - Configure CORS narrowly. Wildcard origins combined with credentials allow any site to make authenticated requests on a user's behalf.
- Authentication is not automatic.
Depends()gives you the mechanism; you still have to implement and apply it to every route that needs it. - Never echo request data into an error message without escaping — that is reflected XSS in the docs UI and log injection elsewhere.
- Terminate TLS and add security headers at the reverse proxy for anything beyond a lab.
- Define Pydantic models for request/response bodies so validation is automatic and explicit.
- Use
Depends()for auth, DB sessions, and shared logic instead of repeating checks. - Serve behind
uvicorn/gunicornwith TLS; disable interactive docs (docs_url=None) in exposed deployments. - Raise
HTTPExceptionwith proper status codes rather than returning ad-hoc error dicts. - Never trust client input — models validate shape, but you still authorize actions.
- [[Flask]] — simpler, synchronous alternative for small listeners
- [[requests]] — client for exercising your FastAPI endpoints
- [[Readme|Python for Security Professionals]] — course home