Skip to content

Use request-body DTOs for environment create/rename endpoints#137

Merged
dmccoystephenson merged 2 commits into
mainfrom
feature/environment-request-body-dtos
Jun 13, 2026
Merged

Use request-body DTOs for environment create/rename endpoints#137
dmccoystephenson merged 2 commits into
mainfrom
feature/environment-request-body-dtos

Conversation

@dmccoystephenson

@dmccoystephenson dmccoystephenson commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Aligns the two environment write endpoints with the OpenAPI contract, which already specifies request bodies and the CreateEnvironmentRequest / UpdateEnvironmentNameRequest schemas that were never implemented (the gap #128 calls out):

Endpoint Before After
Create POST /api/v1/environments/{name}/{numGrids}/{gridSize} POST /api/v1/environments + CreateEnvironmentRequest body {name, numGrids, gridSize}
Rename PATCH /api/v1/environments/{id}/name/{name} PATCH /api/v1/environments/{id}/name + UpdateEnvironmentNameRequest body {name}
  • New DTOs carry the same validation the path variables enforced (@NotBlank name, @Min(1) numGrids/gridSize) via @Valid @RequestBody; invalid input returns 400 through the existing GlobalExceptionHandler.
  • Keeps all three representations in lockstep:
    • Server controller (EnvironmentController).
    • Java client SDK (services/EnvironmentService, consumed by DebugController) — now sends HttpEntity bodies to the new paths instead of the old path-variable URLs (would otherwise 404).
    • Python client (services/environmentService).
  • Updates the MockMvc tests (rewrote the 6 create/rename tests for JSON bodies; added 3 validation tests: blank name, non-positive numGrids, blank rename) and the Python client tests.
  • Updates the drifted docs/MVP.md / docs/PLANNING.md endpoint descriptions, which still documented the path-variable forms.
  • No change to docs/openapi/viron-api.json — the spec was already correct; the code is now aligned to it.

Scope / split

This resolves the environment half of #128. The entity write endpoints are the same anti-pattern but are not defined in the OpenAPI spec at all, so aligning them additionally requires authoring the entity resource in viron-api.json (a wire-contract change needing human review). That work is split into #135 to keep this PR coherent and auto-mergeable. Pre-existing wholesale Postman collection drift is split into #136.

Partially addresses #128 (environment endpoints); does not auto-close it — see #135 for the remaining entity portion.

Known out-of-scope discrepancy

The spec says POST /api/v1/environments returns 200, but the controller returns 201 Created (more correct for a creation). This PR is input-shape-only and leaves the status as-is; tracked in #135 for a spec-accuracy pass.

⚠️ Breaking change

The two endpoints' URLs change. Acceptable pre-MVP; the spec was always the intended contract (confirmed with the maintainer).

Test plan

  • ./mvnw test (full suite) — 216/216 pass (was 213; +3 validation tests), JDK 21
  • pytest src/test/python80/80 pass (Python 3.11). CI does not run Python, so this local run is the Python anchor.
  • Endpoints verified against docs/openapi/viron-api.json (path, verb, body schema match exactly)
  • Java client SDK + Python client both updated to the new contract

🤖 Generated with Claude Code

dmccoystephenson and others added 2 commits June 13, 2026 06:53
Align the two write endpoints on /api/v1/environments with the OpenAPI
contract (docs/openapi/viron-api.json), which already specifies request
bodies and the CreateEnvironmentRequest / UpdateEnvironmentNameRequest
schemas that were never implemented:

- POST /api/v1/environments now takes a CreateEnvironmentRequest body
  ({name, numGrids, gridSize}) instead of POST /{name}/{numGrids}/{gridSize}.
- PATCH /api/v1/environments/{id}/name now takes an UpdateEnvironmentNameRequest
  body ({name}) instead of PATCH /{id}/name/{name}.

Both DTOs carry the validation the old path variables enforced (@notblank
name, @min(1) numGrids/gridSize) via @Valid @RequestBody, so invalid input
returns 400 through the existing GlobalExceptionHandler.

Updates the Python client (environmentService) and its tests to send JSON
bodies, the MockMvc controller tests (including new validation cases), and
the drifted MVP.md / PLANNING.md endpoint descriptions. No change to
viron-api.json: the spec was already correct and the code is now aligned to it.

This is a breaking change to the two endpoints' URLs; it is acceptable
pre-MVP and the spec was always the intended contract.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The RestTemplate-based EnvironmentService (consumed by DebugController)
still built the old path-variable URLs for create/rename, which now 404
after the controller change. Send CreateEnvironmentRequest /
UpdateEnvironmentNameRequest bodies via HttpEntity to the new paths,
keeping the Java client in lockstep with the server and the Python client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@dmccoystephenson dmccoystephenson left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review rubric (adversarial; anchored on green CI run 27467410219 + the diff):

  • Scope: PASS — 9 files, all required for the environment write-endpoint refactor (2 DTOs, controller, Java client SDK, Python client, both test surfaces, the two drifted docs). No unrelated churn.
  • Tests-new: PASS — new endpoint behaviour exercised by the rewritten 6 MockMvc create/rename tests + 3 new validation tests (blank name, non-positive numGrids, blank rename); Python client tests updated to assert the JSON bodies.
  • Sibling structure: PASS — CreateEnvironmentRequest / UpdateEnvironmentNameRequest mirror EnvironmentDto (Lombok @Data/@NoArgsConstructor/@AllArgsConstructor + @Schema) and form a parallel request-DTO pair.
  • Sibling renames: PASS — the key item. The endpoint-shape change was applied across the whole parallel set: server controller, Java client SDK (services/EnvironmentService), Python client, both test surfaces, and MVP.md + PLANNING.md.
  • Docs: PASS — MVP.md + PLANNING.md updated; README already used the body form; viron-api.json already correct (no change). Pre-existing wholesale Postman drift split to #136 rather than partially patched.
  • Issue resolution: PASS (honest partial) — resolves the environment half of #128; the entity half is explicitly split to #135 and this PR does not auto-close #128. No false closure.
  • CI: PASS — build green on PR head.
  • DTO boundary: PASS — createEnvironment still returns EnvironmentDto; no internal model (Environment) leaked.
  • Spec alignment: PASS — POST /api/v1/environments (body CreateEnvironmentRequest) and PATCH /api/v1/environments/{id}/name (body UpdateEnvironmentNameRequest) match viron-api.json exactly. The pre-existing 200-vs-201 response-status discrepancy is left as-is and tracked in #135.
  • Java/Python parallelism: PASS — server + Java client + Python client all updated.
  • Override correctness: PASS — git diff shows zero @Override churn in production.

Substantive finding surfaced AND fixed during review: the first push updated the server, the Python client, and the docs but missed the Java client SDK (services/EnvironmentService, consumed by DebugController), which still built the old path-variable URLs and would have 404'd at runtime. CI would not have caught it (no test covers that client). The adversarial parallelism grep caught it; fixed in the second commit (88129d0). This is exactly the cross-representation drift this repo's loop exists to prevent.

Summary: ready to merge as the environment half of #128; entity half tracked in #135, Postman drift in #136.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant