Skip to content

Releases: Hawk-API/HawkAPI

v0.1.7

16 May 06:43

Choose a tag to compare

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 return statement (optional docstring before it)
  • Return value is Call to Response / PlainTextResponse / JSONResponse / HTMLResponse by 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

16 May 06:31

Choose a tag to compare

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_flags previously lifted X-User-Id / X-Tenant-Id straight into the targeting context — any attacker could claim any user/tenant. Both fields are now always None on the default context.
  • [HIGH · CWE-352] GraphQL mutations no longer sneak through GET. Multi-operation documents with ?operationName=B could 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_handler accepts max_depth=15 and timeout_s=30.0 by default. Wraps executor in asyncio.wait_for.
  • [MEDIUM · CWE-200] GraphiQL UI now opt-in (graphiql=False default).
  • [MEDIUM] gRPC default concurrent-RPC cap of 1000 via new maximum_concurrent_rpcs kwarg.

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

19 Apr 18:31

Choose a tag to compare

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_route re-ran the handler — doubling any side effects. _compute_trivial now 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 raw str; the fast path now calls _coerce_fast (same behaviour as the general path).
  • [MEDIUM] GraphiQL CDN assets pinned + SRI. Default app.mount_graphql(...) ships with graphiql=True; the embedded HTML now uses exact pinned versions (graphiql@3.0.9, react@18.3.1, react-dom@18.3.1) and sha384 SRI 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_route hoisted to module scope.

Added

  • hawkapi doctor --offline — skip rules that require network access (e.g. DOC050's PyPI version check). Rules opt in via requires_network: bool = True.
  • README Security section: always use secrets.compare_digest to compare credentials returned by HTTPBasic / HTTPBearer.

Changed

  • build_mypyc.py documents the MSVC reserved-identifier trap (__is_trivial, __is_class, etc.) so future additions to HOT_MODULES avoid _is_* / _has_* attribute names that collide with C++11 type-trait keywords on Windows.
  • Ruff lint scope tightened: benchmarks/**, examples/**, hatch_build.py excluded from rules that only apply to library code.

Full changelog: https://github.com/ashimov/HawkAPI/blob/v0.1.5/CHANGELOG.md

v0.1.4

19 Apr 15:34

Choose a tag to compare

Highlights

  • hawkapi doctor — new one-shot health-check CLI (18 rules across security, observability, performance, correctness, deps). Human + JSON output, --severity filter, 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-uvloop to opt out.
  • mypyc expansionrouting/router.py and di/resolver.py added 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 reliabilitymypy / setuptools / msgspec added to build-system.requires; [tool.mypy] with follow_imports = silent scoped 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

19 Apr 11:11

Choose a tag to compare

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-inferred response_model
  • DX parity with FastAPI — route-level dependencies=, response_model_exclude_* flags, OAuth2 scopes, hawkapi.status constants
  • 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
  • Migrationhawkapi migrate codemod for FastAPI → HawkAPI

Added

Transports

  • app.mount_grpc(servicer, add_to_server=..., port=50051) — gRPC integration over grpc.aio: ASGI lifespan-tied server lifecycle, built-in HawkAPIObservabilityInterceptor (structured logging + Prometheus metrics), context injection (context.hawkapi_app, context.hawkapi_request_id), reflection toggle with reflection_service_names, TLS passthrough via ssl_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 via context_factory, optional from_graphql_core and from_strawberry adapters behind lazy imports

Feature flags

  • FlagProvider Protocol, StaticFlagProvider / EnvFlagProvider / FileFlagProvider (mtime hot-reload, JSON/TOML/YAML)
  • Flags facade, Depends(get_flags) DI helper with per-request EvalContext
  • @requires_flag decorator (404 on off), plugin hook on_flag_evaluated

Client codegen

  • hawkapi gen-client CLI: zero-dep TypeScript (native fetch) + Python (msgspec) SDKs from OpenAPI 3.1

Typed routes

  • response_model auto-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, OpenAPI operation.security reflection

Concurrency primitives

  • hawkapi.middleware.Bulkhead — named async concurrency isolator with context-manager and @bulkhead(...) decorator forms
  • LocalBulkheadBackend (default) and RedisBulkheadBackend (distributed, hash + lease-TTL)
  • Prometheus metrics: hawkapi_bulkhead_in_flight, _capacity, _rejections_total, _acquire_latency_seconds

Free-threaded Python 3.13

  • cp313t-cp313t wheels via cibuildwheel (experimental)
  • hawkapi._threading module: FREE_THREADED flag, 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 - Unstable trove classifier

Migration and CI

  • hawkapi migrate codemod — 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.md
  • docs/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