🔬 API Autopsy
Production-grade API performance analysis for Django and FastAPI.
Automatically detect performance issues — N+1 queries, blocking async calls, slow serializers — without external APM services.
⚡ Quickstart
Install
pip install api-autopsy
Django
# settings.py
INSTALLED_APPS += ["api_autopsy"]
MIDDLEWARE += ["api_autopsy.integrations.django.middleware.APIAutopsyMiddleware"]
FastAPI
from fastapi import FastAPI
from api_autopsy.integrations.fastapi import APIAutopsyMiddleware
app = FastAPI()
app.add_middleware(APIAutopsyMiddleware)
That's it. Visit /api-autopsy/ to see the dashboard.
🎯 What It Detects
| Category | Detection |
|---|---|
| N+1 Queries | Repeated SQL patterns across a single request |
| Duplicate Queries | Identical SQL executed multiple times |
| Slow Queries | Individual queries exceeding thresholds |
| Missing Indexes | Slow WHERE clauses on non-primary columns |
| Slow Serializers | DRF serializer timing and nested cost |
| Async Violations | time.sleep(), requests.* in async handlers |
| Memory Bloat | Per-request memory allocation deltas |
| External Calls | Outbound HTTP call count and timing |
Every detection comes with actionable recommendations.
📊 Performance Score
Each endpoint receives a 0–100 score based on:
- Latency (30%) — exponential decay from ideal threshold
- Query Efficiency (30%) — penalizes count, duplicates, N+1
- Memory Usage (20%) — penalizes large allocation deltas
- Async Correctness (20%) — binary penalties for blocking calls
🖥️ Dashboard
Auto-served at /api-autopsy/ with:
- Endpoint ranking table (sortable by score, latency, queries)
- Performance timeline (5-minute buckets over 24h)
- Slow endpoint heatmap (by hour)
- Analysis findings with severity and recommendations
- Dark/light mode toggle
- Auto-refresh every 30s
🔧 Configuration
Django
# settings.py
API_AUTOPSY = {
"ENABLED": True,
"STORAGE_BACKEND": "sqlite", # sqlite | postgres | redis
"STORAGE_DSN": "autopsy.db",
"SAMPLE_RATE": 1.0, # 0.0–1.0
"RETENTION_HOURS": 72,
"DASHBOARD_PREFIX": "/api-autopsy",
}
FastAPI
from api_autopsy.config import configure
configure(
sample_rate=0.1, # 10% sampling in production
retention_hours=48,
storage_dsn="/var/data/autopsy.db",
)
🚀 CI/CD Mode
# Generate JSON report
api-autopsy analyze --format json --output report.json
# Fail CI if score drops below threshold
api-autopsy analyze --threshold 70
# Detect regression against a baseline
api-autopsy analyze --baseline baseline.json --threshold 10
# Cleanup old data
api-autopsy cleanup --hours 24
Exit codes: 0 = pass, 1 = regression or critical findings.
🔌 Extensibility
Custom Analyzer
from api_autopsy.plugins import register_analyzer
from api_autopsy.analyzers.base import BaseAnalyzer
from api_autopsy.core.context import Finding
@register_analyzer
class MyCustomAnalyzer(BaseAnalyzer):
def analyze(self, ctx):
findings = []
if ctx.duration_ms > 1000:
findings.append(Finding(
severity="warning",
category="slow_response",
message=f"Response took {ctx.duration_ms:.0f}ms",
recommendation="Consider caching or pagination.",
))
return findings
Via Entry Points
# pyproject.toml
[project.entry-points."api_autopsy.plugins"]
my_plugin = "my_package.autopsy:register"
🏗️ Architecture
api_autopsy/
├── config.py # Central configuration + auto-detection
├── plugins.py # Plugin discovery system
├── core/
│ ├── context.py # contextvars-based RequestContext
│ └── registry.py # Collector/Analyzer registry
├── collectors/
│ ├── base.py # Abstract collector
│ ├── timing.py # Request duration
│ ├── sql.py # SQL queries + duplicates
│ ├── memory.py # Memory delta (tracemalloc)
│ ├── http_calls.py # Outbound HTTP tracking
│ └── cache.py # Cache hit/miss tracking
├── analyzers/
│ ├── base.py # Abstract analyzer
│ ├── orm.py # N+1, duplicates, slow queries
│ ├── serializer.py # DRF serializer profiling
│ └── async_safety.py # Blocking I/O detection
├── scoring/
│ └── engine.py # Weighted 0–100 scoring
├── storage/
│ ├── base.py # Abstract storage
│ └── sqlite.py # SQLite backend (default)
├── dashboard/
│ ├── views.py # Django + ASGI handlers
│ └── templates/
│ └── index.html # Dashboard UI
├── integrations/
│ ├── django/
│ │ ├── apps.py # Django AppConfig
│ │ └── middleware.py # WSGI middleware
│ └── fastapi/
│ └── middleware.py # ASGI middleware
└── cli/
└── main.py # CLI entry point
🧪 Testing
pip install -e ".[dev]"
pytest tests/ -v
Production Safety
- Sampling: Set
sample_rateto0.01–0.1for high-traffic - Overhead: < 5% with sampling; collectors are lightweight
- Retention: Auto-cleanup via
retention_hoursor CLI - Async-safe: Uses
contextvars— no thread-local issues
License
MIT
Metadata
Release files for api-autopsy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| api_autopsy-0.1.0.tar.gz | 27.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| api_autopsy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.4 kB
Release files / api_autopsy-0.1.0.tar.gz
| Download URL | api_autopsy-0.1.0.tar.gz |
|---|---|
| Size | 27.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0de0479d52657649c3c714bddaadb2d0e21dea216fe795e3ed4367e2ae014862
|
|
BLAKE2b-256 checksum How to use checksums |
4c567682e8c910c94c2f9176b7538974e97a3a94e6f65cf1b7cab528c05c9770
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / api_autopsy-0.1.0-py3-none-any.whl
| Download URL | api_autopsy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 40.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
29fb845ba9af56e69c5ddc0323019da3cf4434b8461c386e36cd31f32c9560fc
|
|
BLAKE2b-256 checksum How to use checksums |
bdb31b9f54e57d1f73c823ef0f0bc2294c9bf59fa1e3bd3ca692e620aca7499b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Security for api-autopsy 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.