## Implementation Plan: Add Nullable Annotations to Custom /docs API Definition ### 1. Modified Files & Changes | File | Change | |---|---| | `devplacepy/docs_api/_shared.py` | Add `nullable: bool = False` parameter to `field()`. Store it in the field metadata dictionary. | | `devplacepy/docs_examples.py` | Update `schema_example()`: after generating a sample value via `_unwrap_optional()`, if the field has `nullable=True` and the generated value is not already `None`, replace it with `None` (JSON `null`). Also append `" (nullable)"` to the field’s label or description in the generated example dict. | | `devplacepy/routers/profile.py` (or wherever `ProfileOut` endpoint is defined) | In the `field()` call for the `projects` list member (or the relevant response field), add `nullable=True` for each Optional field that is currently nullable. For example: `field(name="updated_at", type=str, nullable=True)`. If the router uses a shared schema definition, add annotations there. | | `static/js/ApiTester.js` (approximate path: `devplacepy/static/` or `docs_api/static/`) | In `renderExpected()` (line ~318), check if the field object has a `nullable` property. If true, append a small badge or label like `[nullable]` next to the field name in the JSON sample (e.g., as a comment or in a separate column). Alternative: render the sample value as `null` with a tooltip. | | New test file: `tests/unit/test_docs_nullable.py` | Write unit tests that:
– Verify `field(nullable=True)` sets the metadata correctly.
– Verify `schema_example()` produces `null` for a nullable field.
– Verify the rendered JSON snippet in `ApiTester.js` includes a nullability indicator (requires a Playwright screenshot or DOM assertion – optional if unit tests for Python logic are sufficient). | ### 2. Detailed Steps (for a competent engineer) **Step A** – In `devplacepy/docs_api/_shared.py`: - Add `nullable: bool = False` to the function signature of `field()`. - Inside `field()`, add a key `"nullable"` to the returned dict (or to the field metadata) set to the value of `nullable`. **Step B** – In `devplacepy/docs_examples.py`: - Locate the `_unwrap_optional()` call (line ~45). After resolving the final type and generating a default sample, check if the field’s metadata dict has `"nullable": True`. - If so, replace the generated sample value with `None` (JSON `null`) in the output dict. - Also modify the field’s label string (if any) to append `" (nullable)"`. **Step C** – Update router definitions: - Find all endpoints that use `ProjectOut` or `ProfileOut` and whose `field()` calls currently lack `nullable=True` for Optional fields. - Add `nullable=True` to `field(name="updated_at", ...)`. - Repeat for other fields that are `Optional[...]` in the Pydantic schemas but are only referenced through the `field()` function for /docs (the router might not use `field()` at all – if that’s the case, skip and the sample generator will infer nullability from the Pydantic model if the model is used directly. The ticket’s custom docs may not use Pydantic models directly; it uses `field()` calls. We must assume that each endpoint manually lists fields via `field()` – verify in the code). **Step D** – Modify `ApiTester.js`: - In the `renderExpected()` method, iterate over the fields of the example response (the sample object). If a field metadata has `nullable: true`, add a small attribute or CSS class to the rendered `` element, or insert a `nullable` after the field name for human readers. **Step E** – Write unit tests: - `test_field_nullable_parameter()` calls `field(nullable=True)` and checks returned dict. - `test_schema_example_nullable_field()` creates a mock schema with a nullable field and calls `schema_example()`, asserts `None` appears in output. - (Optional) `test_api_tester_renders_nullable()` uses Playwright to open the /docs page for a known endpoint and checks that the nullable badge is present. ### 3. Definition of Done - [ ] The `field()` function in `devplacepy/docs_api/_shared.py` accepts `nullable: bool = False` and stores it. - [ ] The `schema_example()` function in `devplacepy/docs_examples.py` returns `null` in JSON for any field marked `nullable=True`. - [ ] All endpoints that return `ProjectOut` or `ProfileOut` have their `field()` definitions updated to pass `nullable=True` on fields like `updated_at`. - [ ] The custom /docs page displays a visual indicator (badge or label) next to nullable fields in the sample response. - [ ] All existing unit tests pass. - [ ] The project’s verification command succeeds: ``` pip install -e '.[dev]' -q && python -m pytest tests/unit/test_docs_nullable.py tests/unit/test_docs_examples.py tests/unit/test_shared.py ``` (or the minimal set of test files that cover the changed modules; if no such files exist, create them as part of the plan and ensure they pass.) - [ ] No regression in the previously failed e2e tests (those tests failed due to Playwright environment issues unrelated to this change; the new code must not introduce additional Playwright failures – run `pytest tests/e2e/` in a compatible environment to confirm).