Releases: Hawk-API/HawkAPI
v0.1.7
Static-response cache — Wave 4
Handlers whose body is exactly return SomeResponse(literal_args) with no parameters now have their two ASGI messages built once at registration time via AST inspection and re-emitted directly on every request — no handler call, no Response allocation, no header construction per request.
Micro-benchmark (Darwin / Python 3.13, ASGI-level)
| Per-request | Throughput | |
|---|---|---|
| Wave 3 trivial fast path (0.1.6) | 6.76 µs | 148 k req/s |
| Wave 4 static cache (0.1.7) | 0.89 µs | 1 126 k req/s |
7.5× speedup at the framework level. Real HTTP-server overhead (Granian + wrk) dominates per-request time at this point — we expect the Linux competitive bench to take #1 in plaintext away from BlackSheep (which currently leads at 165 k req/s).
Detection (AST-only, no handler invocation at registration)
- No parameters of any kind
- Single
returnstatement (optional docstring before it) - Return value is
CalltoResponse/PlainTextResponse/JSONResponse/HTMLResponseby bare name - All positional and keyword arguments are literals (
Constant/ list / tuple / set / dict / unary +/- of constants)
Any deviation falls through to the existing trivial / general fast paths — no behavioural regression for dynamic handlers.
Added
- README now leads with a Why HawkAPI matrix (Performance / Production rigor / Features no one else has) and a dedicated p99 latency table showing tail-behaviour wins.
Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.7/CHANGELOG.md
v0.1.6
Security audit release
Full security audit (Bandit + Semgrep + pip-audit + Gitleaks + CodeQL), STRIDE threat-model per subsystem, OWASP API Top 10 compliance map, and fixes for 3 HIGH and 2 MEDIUM findings.
Security
- [HIGH · CWE-290] flags identity headers no longer trusted.
get_flagspreviously liftedX-User-Id/X-Tenant-Idstraight into the targeting context — any attacker could claim any user/tenant. Both fields are now alwaysNoneon the default context. - [HIGH · CWE-352] GraphQL mutations no longer sneak through GET. Multi-operation documents with
?operationName=Bcould bypass the first-token check. The handler now parses every operation and rejects GET for any non-query. - [HIGH · CWE-770] GraphQL depth + timeout limits.
make_graphql_handleracceptsmax_depth=15andtimeout_s=30.0by default. Wraps executor inasyncio.wait_for. - [MEDIUM · CWE-200] GraphiQL UI now opt-in (
graphiql=Falsedefault). - [MEDIUM] gRPC default concurrent-RPC cap of 1000 via new
maximum_concurrent_rpcskwarg.
Added
SECURITY.md(responsible disclosure)docs/security/threat-model.md(STRIDE per subsystem)docs/security/code-review-2026-05-16.md(focused review)docs/security/owasp-api-top10-2023.md(compliance map).github/workflows/security.yml(5 scanners on every push/PR + weekly).github/dependabot.yml(weekly pip + actions updates)
Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.6/CHANGELOG.md
v0.1.5
Security & correctness fixes
All findings from the full code review of 0.1.4 are addressed here.
Fixed
- [HIGH] Double-execution of handler on StreamingResponse/FileResponse. Wave 3's trivial fast path classified these handlers as trivial; a late fallback to
_execute_routere-ran the handler — doubling any side effects._compute_trivialnow inspects the return annotation and excludes streaming returns at registration time. - [MEDIUM] Path-param coercion missing on the trivial fast path.
{id:int}-style typed path params were passed as rawstr; the fast path now calls_coerce_fast(same behaviour as the general path). - [MEDIUM] GraphiQL CDN assets pinned + SRI. Default
app.mount_graphql(...)ships withgraphiql=True; the embedded HTML now uses exact pinned versions (graphiql@3.0.9,react@18.3.1,react-dom@18.3.1) andsha384SRI hashes on every script / stylesheet — closes the supply-chain vector. - [LOW] FileFlagProvider cache/mtime write order. Under free-threaded CPython / thread-pool workers, readers could observe a new mtime + stale cache. Cache is now written first, mtime last.
- [LOW] Lazy imports inside
_execute_trivial_routehoisted to module scope.
Added
hawkapi doctor --offline— skip rules that require network access (e.g. DOC050's PyPI version check). Rules opt in viarequires_network: bool = True.- README Security section: always use
secrets.compare_digestto compare credentials returned byHTTPBasic/HTTPBearer.
Changed
build_mypyc.pydocuments the MSVC reserved-identifier trap (__is_trivial,__is_class, etc.) so future additions toHOT_MODULESavoid_is_*/_has_*attribute names that collide with C++11 type-trait keywords on Windows.- Ruff lint scope tightened:
benchmarks/**,examples/**,hatch_build.pyexcluded from rules that only apply to library code.
Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.5/CHANGELOG.md
v0.1.4
Highlights
hawkapi doctor— new one-shot health-check CLI (18 rules across security, observability, performance, correctness, deps). Human + JSON output,--severityfilter, exit codes 0/1/2. See docs/guide/doctor.md.- Trivial-route fast path — routes without DI / deps / permissions / background / response_model / deprecation / per-route middleware now bypass the general execution path and dispatch straight to the handler. Local benchmark: plaintext 148 k → ~162 k req/s (≥ 8 %), targeted at the #1 plaintext slot vs BlackSheep.
- uvloop-by-default in
hawkapi dev(when installed).--no-uvloopto opt out. - mypyc expansion —
routing/router.pyanddi/resolver.pyadded to compiled hot modules. - Using HawkAPI? badge — new
docs/assets/hawk-icon.svg+ "Using HawkAPI?" README section with copy-paste Markdown/reStructuredText snippets for downstream projects (dynamic PyPI version badge). - Build reliability —
mypy/setuptools/msgspecadded tobuild-system.requires;[tool.mypy]withfollow_imports = silentscoped type-check to compiled modules; license declaration switched to PEP 621 table form for cp312 pip compatibility; cibuildwheel smoke-test simplified to import check.
Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.4/CHANGELOG.md
v0.1.3
Highlights
- Tier 2 complete — bulkhead primitive, feature flags, GraphQL thin mount, gRPC thin mount
- Tier 1 — free-threaded Python 3.13 wheels (cp313t), PEP 703-aware locking helpers
- Tier 3 — OpenAPI TS/Python client codegen (
hawkapi gen-client), typed routes with auto-inferredresponse_model - DX parity with FastAPI — route-level
dependencies=,response_model_exclude_*flags, OAuth2 scopes,hawkapi.statusconstants - Distributed primitives — Redis-backed circuit breaker and adaptive concurrency limiter
- CI — competitive benchmarks (weekly + release), performance regression gate (5 % threshold), memory budget tests via pytest-memray
- Migration —
hawkapi migratecodemod for FastAPI → HawkAPI
Added
Transports
app.mount_grpc(servicer, add_to_server=..., port=50051)— gRPC integration overgrpc.aio: ASGI lifespan-tied server lifecycle, built-inHawkAPIObservabilityInterceptor(structured logging + Prometheus metrics), context injection (context.hawkapi_app,context.hawkapi_request_id), reflection toggle withreflection_service_names, TLS passthrough viassl_credentials, port-merge for multi-servicer setups; zero runtime deps (grpcio imported lazily)app.mount_graphql(path, executor=...)— GraphQL-over-HTTP adapter: POST + GET wire protocol, GraphiQL UI, context injection viacontext_factory, optionalfrom_graphql_coreandfrom_strawberryadapters behind lazy imports
Feature flags
FlagProviderProtocol,StaticFlagProvider/EnvFlagProvider/FileFlagProvider(mtime hot-reload, JSON/TOML/YAML)Flagsfacade,Depends(get_flags)DI helper with per-requestEvalContext@requires_flagdecorator (404 on off), plugin hookon_flag_evaluated
Client codegen
hawkapi gen-clientCLI: zero-dep TypeScript (native fetch) + Python (msgspec) SDKs from OpenAPI 3.1
Typed routes
response_modelauto-inferred from handler return annotation (msgspec Structs, Pydantic models, generics, Optionals)
FastAPI parity
hawkapi.status— HTTP and WebSocket status-code constants- Route-level
response_model_exclude_none / _unset / _defaults(recursive, zero-overhead when off) - Route-level and router-level
dependencies=[Depends(...)] Security(dep, *, scopes=[...]),SecurityScopes, per-route scope aggregation, OpenAPIoperation.securityreflection
Concurrency primitives
hawkapi.middleware.Bulkhead— named async concurrency isolator with context-manager and@bulkhead(...)decorator formsLocalBulkheadBackend(default) andRedisBulkheadBackend(distributed, hash + lease-TTL)- Prometheus metrics:
hawkapi_bulkhead_in_flight,_capacity,_rejections_total,_acquire_latency_seconds
Free-threaded Python 3.13
cp313t-cp313twheels via cibuildwheel (experimental)hawkapi._threadingmodule:FREE_THREADEDflag,maybe_thread_lock(),maybe_async_lock()build_mypyc.is_enabled()auto-skips mypyc compilation on free-threaded interpreters- PEP 779
Programming Language :: Python :: Free Threading :: 1 - Unstabletrove classifier
Migration and CI
hawkapi migratecodemod — AST-driven FastAPI → HawkAPI rewrites- Performance regression gate: committed baseline +
pytest-benchmark --benchmark-compare-fail - Memory budget tests via pytest-memray
- Competitive benchmark CI (weekly cron + release trigger, wrk on ubuntu-latest, auto-PR of refreshed
RESULTS.md) - Redis-backed circuit breaker (
RedisCircuitBreakerMiddleware) - Adaptive concurrency limiter middleware
- HTTP/2 deployment guide
Docs
docs/guide/grpc.md,docs/guide/graphql.md,docs/guide/feature-flags.mddocs/guide/bulkhead.md,docs/guide/free-threaded.md,docs/guide/benchmarks.md
Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.3/CHANGELOG.md