FastAPI skeleton for Feature 16, first task (042dfc5c): health, OpenAPI, core wiring.
Done-condition: A FastAPI app in api/ imports core/, starts against a SQLite path from configuration, and serves GET /health returning 200 with a status body. The OpenAPI document is served at /docs. A test starts the app with httpx and asserts both.
What this adds
api/nestquest_core.py — transitional coupling: bootstraps the integration directory onto sys.path and imports core as a top-level package, so custom_components/nestquest/__init__.py (which imports homeassistant) never executes. Encapsulated in one documented helper to revisit in Feature 18.
api/config.py — reads NESTQUEST_DB_PATH (env var, documented temp default).
api/database.py — opens+migrates the SQLite database via the bundled NestQuestDatabase / apply_migrations, using an asyncio.to_thread executor mirroring hass.async_add_executor_job.
api/app.py — FastAPI app with a lifespan that opens+migrates on startup and closes on shutdown; serves GET /health (200, status: ok + resolved db_path) and the auto OpenAPI at /docs and /openapi.json.
tests/test_api_health.py — httpx against the ASGI app asserts /health (200 + body), /openapi.json, and /docs; a hermetic test re-opens the temp db and asserts migrations ran (schema version stamped); a subprocess test proves the app imports core WITHOUT importing homeassistant or registering custom_components (the suite conftest stubs HA, so the honest proof is a clean subprocess).
pyproject.toml — add fastapi, uvicorn, httpx to the dev dependency group; uv lock.
Verification
uv run pytest -q green at 1581 (1576 baseline + 5 new API tests).
No-HA invariant: homeassistant and custom_components are absent from sys.modules after building the app in a clean subprocess.
No lint/typecheck tool is configured for this repo (pyproject has only pytest); py_compile and ast.parse clean on all new files.
FastAPI skeleton for Feature 16, first task (042dfc5c): health, OpenAPI, core wiring.
**Done-condition:** A FastAPI app in `api/` imports `core/`, starts against a SQLite path from configuration, and serves `GET /health` returning 200 with a status body. The OpenAPI document is served at `/docs`. A test starts the app with httpx and asserts both.
**What this adds**
- `api/nestquest_core.py` — transitional coupling: bootstraps the integration directory onto `sys.path` and imports `core` as a top-level package, so `custom_components/nestquest/__init__.py` (which imports `homeassistant`) never executes. Encapsulated in one documented helper to revisit in Feature 18.
- `api/config.py` — reads `NESTQUEST_DB_PATH` (env var, documented temp default).
- `api/database.py` — opens+migrates the SQLite database via the bundled `NestQuestDatabase` / `apply_migrations`, using an `asyncio.to_thread` executor mirroring `hass.async_add_executor_job`.
- `api/app.py` — FastAPI app with a lifespan that opens+migrates on startup and closes on shutdown; serves `GET /health` (200, `status: ok` + resolved `db_path`) and the auto OpenAPI at `/docs` and `/openapi.json`.
- `tests/test_api_health.py` — httpx against the ASGI app asserts `/health` (200 + body), `/openapi.json`, and `/docs`; a hermetic test re-opens the temp db and asserts migrations ran (schema version stamped); a subprocess test proves the app imports `core` WITHOUT importing `homeassistant` or registering `custom_components` (the suite conftest stubs HA, so the honest proof is a clean subprocess).
- `pyproject.toml` — add `fastapi`, `uvicorn`, `httpx` to the dev dependency group; `uv lock`.
**Verification**
- `uv run pytest -q` green at 1581 (1576 baseline + 5 new API tests).
- No-HA invariant: `homeassistant` and `custom_components` are absent from `sys.modules` after building the app in a clean subprocess.
- No lint/typecheck tool is configured for this repo (pyproject has only pytest); `py_compile` and `ast.parse` clean on all new files.
Task: NestQuest tracker 042dfc5c-9082-4db9-9539-790cd21f5308 (Feature 16).
Add api/ with a FastAPI app that imports the bundled NestQuest core
(Feature 15) WITHOUT importing homeassistant: api/nestquest_core.py
bootstraps the integration directory onto sys.path and imports core as
a top-level package, so custom_components/nestquest/__init__.py (which
imports HA) never executes. This transitional coupling is encapsulated
in one documented helper to revisit in Feature 18.
The app reads NESTQUEST_DB_PATH (env var, documented temp default),
opens+migrates the SQLite database in a FastAPI lifespan, and serves
GET /health (200, status ok + resolved db_path) and the OpenAPI doc at
/docs and /openapi.json. Tests start the app with httpx against the
ASGI app and assert all three; a subprocess test proves the app
imports core without importing homeassistant or registering
custom_components.
Add fastapi, uvicorn, httpx to the dev dependency group; uv lock.
Suite green at 1581 (1576 baseline + 5 new API tests).
P2-1 (containment): api/nestquest_core.py no longer mutates sys.path.
Load core by file location with importlib.util.spec_from_file_location,
registering it under the distinct top-level name 'nestquest_core' with
submodule_search_locations pointing at the bundled core directory. No
generic top-level names (db, const, schema, ...) are published that
could shadow a future dependency, and the integration's HA-coupled
__init__ is never executed. Use importlib.import_module for submodules;
drop the redundant _BOOTSTRAPPED flag. Document that two core copies
(nestquest_core.* and custom_components.nestquest.core.*) coexist in
the pytest process so later tasks must not compare class/exception
identity across them.
P2-2 (fail fast): ApiConfig.from_env now RAISES ConfigError when
NESTQUEST_DB_PATH is unset or empty — no silent fallback to a
predictable world-writable temp path that loses data at reboot. Remove
the module-level 'app = create_app()' (it read env at import time and
would break fail-fast); document serving with 'uvicorn --factory
api.app:create_app'.
P3 cleanups:
- /health drops db_path from the body (no filesystem path leak on an
unauthenticated route) and runs a cheap SELECT 1 to reflect database
reachability.
- Remove dead code: resolve_db_path in api/config.py; unused LOGGER in
api/app.py.
- tests/test_api_health.py: add ApiConfig.from_env tests (set value,
empty raises, missing raises); add startup-failure tests (unwritable
dir, non-SQLite file); assert shutdown closes the connection
(connected is False); make _AppRunner.__aexit__ use try/finally so a
client error still shuts down the lifespan; reuse api.database._executor
instead of a duplicated local copy; in the no-HA subprocess test
assert core.__file__ points at the bundled directory and stop passing
the unused ':memory:'.
- pyproject.toml: comment that fastapi/uvicorn are dev-group only so the
monorepo test venv can exercise the app; the API deployable's runtime
dependencies must be declared when it is packaged (Feature 17).
dev_agent
merged commit 7fec3c76ef into feature/cd03735b-2498-4b34-b84c-c1cb2b271ba7-nestquest-api-service2026-09-21 16:13:42 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
FastAPI skeleton for Feature 16, first task (042dfc5c): health, OpenAPI, core wiring.
Done-condition: A FastAPI app in
api/importscore/, starts against a SQLite path from configuration, and servesGET /healthreturning 200 with a status body. The OpenAPI document is served at/docs. A test starts the app with httpx and asserts both.What this adds
api/nestquest_core.py— transitional coupling: bootstraps the integration directory ontosys.pathand importscoreas a top-level package, socustom_components/nestquest/__init__.py(which importshomeassistant) never executes. Encapsulated in one documented helper to revisit in Feature 18.api/config.py— readsNESTQUEST_DB_PATH(env var, documented temp default).api/database.py— opens+migrates the SQLite database via the bundledNestQuestDatabase/apply_migrations, using anasyncio.to_threadexecutor mirroringhass.async_add_executor_job.api/app.py— FastAPI app with a lifespan that opens+migrates on startup and closes on shutdown; servesGET /health(200,status: ok+ resolveddb_path) and the auto OpenAPI at/docsand/openapi.json.tests/test_api_health.py— httpx against the ASGI app asserts/health(200 + body),/openapi.json, and/docs; a hermetic test re-opens the temp db and asserts migrations ran (schema version stamped); a subprocess test proves the app importscoreWITHOUT importinghomeassistantor registeringcustom_components(the suite conftest stubs HA, so the honest proof is a clean subprocess).pyproject.toml— addfastapi,uvicorn,httpxto the dev dependency group;uv lock.Verification
uv run pytest -qgreen at 1581 (1576 baseline + 5 new API tests).homeassistantandcustom_componentsare absent fromsys.modulesafter building the app in a clean subprocess.py_compileandast.parseclean on all new files.Task: NestQuest tracker 042dfc5c-9082-4db9-9539-790cd21f5308 (Feature 16).