Skip to content

fix(api): complete the error mapping and test it through HTTP - #23

Merged
MendesMat merged 7 commits into
mainfrom
fix/api-error-mapping-follow-ups
Sep 28, 2026
Merged

MendesMat merged 7 commits into
mainfrom
fix/api-error-mapping-follow-ups

Conversation

@MendesMat

Copy link
Copy Markdown
Owner

Part of #6 (follow-ups found in the review after #22 was merged)

What

Fixes the gaps between the error mapping merged in #22 and the documentation, adds the real HTTP integration tests the issue asked for, adds the missing IQueryHandler, and updates the agent guides.

Why

  • Every ADR-0009 code is mapped. The domain already returns link_invalid, system_record, self_deactivation and not_inactive; the table did not list them, so they would have become 500 responses. account_inactive maps to 401 (during a session); the sign-in endpoint returns its 403 explicitly.
  • An unmapped code is an unexpected failure (API-12). It used to return a 500 exposing the code and its message, with nothing logged. It now throws, so the exception handler logs it and answers with unexpected_error (API-14).
  • Typed result (ADR-0003). error.ToProblem() returns ProblemHttpResult, so endpoints can declare Results<Ok<T>, ProblemHttpResult> for the OpenAPI document. Its unused HttpContext parameter is gone.
  • Real integration tests (issue Application and API building blocks: handlers, validation and error responses #6 "Done when"). The first attempt failed because an IStartupFilter receives a plain ApplicationBuilder, not an IEndpointRouteBuilder, so the test endpoints were never mapped. With UseRouting + UseEndpoints, ErrorResponseTests now checks through the whole pipeline the documented validation JSON, the generic 500 for an exception and for an unmapped code. That also covers the exception handler wiring in Program.cs, which no test exercised before.
  • IQueryHandler<TQuery, TResponse> was in the scope of Application and API building blocks: handlers, validation and error responses #6 and was missed.
  • Docs: API-15 (the validation_failed message, which only appeared in an example); the architecture guide describes ToProblem, the code table, account_inactive and how a handler turns a field-less value object error into a field error; the testing guide gains the startup filter and DefaultHttpContext gotchas and loses the stale TEMPORARY notes; rule 3 of AGENTS.md and the git workflow now cover pull request bodies.

How to test

dotnet test --solution ControlService.slnx

137/137 pass, build with 0 warnings, dotnet format --verify-no-changes clean.

Checklist

  • Developed test-first (ADR-0033), in autonomous mode at the owner's request. The table and the unmapped-code behavior started Red. ErrorResponseTests had no Red: it covers wiring of existing behavior; unregistering the exception handler makes both 500 tests fail. IQueryHandler is an interface with no behavior.
  • dotnet test --solution ControlService.slnx passes locally
  • Documentation updated (docs/api/conventions.md, docs/agents/, AGENTS.md)
  • Rule IDs: API-12, API-13, API-14, API-15 (new), ADR-0003, ADR-0007, ADR-0009
  • User-facing messages are verbatim (API-14, API-15)

The domain already returns link_invalid, system_record,
self_deactivation and not_inactive, which the table did not list, so
they would have become 500 responses. account_inactive maps to 401
(during a session); the sign-in endpoint returns its 403 explicitly.
API-12 says a 500 carries only the generic message and the details go
to the logs. Returning the unmapped code and its message in a 500
exposed them and logged nothing; throwing lets the exception handler
log it and answer with unexpected_error.
ADR-0003 asks endpoints to return typed results so the OpenAPI
document can describe them; ProblemHttpResult lets an endpoint declare
Results<Ok<T>, ProblemHttpResult>. The HttpContext parameter was left
unused once ASP.NET Core became the source of traceId, so it is gone.
Issue #6 asked for an integration test of the documented error JSON.
The first attempt mapped test-only endpoints only when the app was an
IEndpointRouteBuilder, but a startup filter receives a plain
ApplicationBuilder, so nothing was mapped. With UseRouting and
UseEndpoints the endpoints run after UseExceptionHandler, which also
covers the exception handler wiring that no test exercised.

No Red: these cover wiring of existing behavior. Unregistering the
exception handler makes both 500 tests fail. The unit tests they
replace (exact JSON, traceId, the handler in isolation) are removed.
Part of the issue #6 scope that was missed. An interface with no
behavior has no meaningful Red; the first real query (issue #10)
exercises it.
- API-15 records the verbatim message of validation_failed, which only
  appeared in an example.
- The architecture guide describes ToProblem, the code table,
  account_inactive (401 by default, 403 at sign-in) and how a handler
  turns a field-less value object error into a field error.
- The testing guide gains the startup-filter and DefaultHttpContext
  gotchas; the TEMPORARY exit-code notes are gone, since no project
  has that line any more.
- Rule 3 of AGENTS.md and the git workflow now cover pull request
  bodies, because a squash merge copies them into main.
@MendesMat
MendesMat enabled auto-merge (squash) September 28, 2026 05:04
@MendesMat
MendesMat merged commit 02bd38b into main Sep 28, 2026
5 checks passed
@MendesMat
MendesMat deleted the fix/api-error-mapping-follow-ups branch September 28, 2026 05:05
MendesMat added a commit that referenced this pull request Sep 28, 2026
…output check script (#25)

## What

Documents how an issue is worked on with agents after the lessons of
issue #6, and adds `check.ps1`, a single command that formats, builds
and tests with short output.

## Why

Issue #6 showed three problems:

- **Cost.** One long conversation carried the survey, 13 TDD cycles and
the review; repeated `ENDOFLINE` listings and full test logs filled it,
and every line is paid again on each reply.
- **Improvised decisions.** Where the plan was vague, the build step
filled the gap by guessing, and one guess contradicted API-12.
- **Late review.** The review happened after the merge, so its fixes
needed a second pull request (#23).

## What changes

- **Three sessions per issue**
(`docs/agents/workflows/implement-a-feature.md`, section *Sessions* and
new step 9):
- plan, ending with a *plan comment* on the issue: decisions, new
messages, and the test list with the expected result of each test;
  - build, which follows that comment instead of repeating the survey;
  - review in a new conversation, before the owner merges.
- **Owner's guide** (`docs/agents/trabalhando-com-agentes.md`, in
Portuguese): which model and effort to use in each session, what to
paste to start each one, when to use pair or autonomous mode, when to
switch models, and how to watch the quota.
- **`check.ps1`** (`backend/ControlService`): runs `dotnet format`, then
the build, then the tests. It prints only problems and summaries, and
keeps the whole test output when a test fails, as the evidence of a Red.
It replaces the separate commands in `AGENTS.md`, the testing guide, the
git workflow and the backend README.
- **`AGENTS.md`**: asks for short tool output, and treats a failed
approach from the approved plan as a stop point.
- **TDD workflow**: commit before each pause and show it in the report.
- **Communication guide**: the plan comment is part of the normal flow,
so it does not need a separate confirmation.

## How to test

```bash
powershell.exe -NoProfile -File backend/ControlService/check.ps1
```

Checked on three runs:

- the whole solution: 137/137, exit 0;
- a filtered run: 9/9, exit 0;
- a throwaway failing test written with LF line endings: the endings
were fixed silently, the failure was printed in full, and the exit code
was 2.

The relative links of every changed document resolve.

## Checklist

- [x] Developed test-first (ADR-0033): not applicable, documentation and
a tooling script, checked by the runs above
- [x] `dotnet test --solution ControlService.slnx` passes locally
- [x] Documentation updated (`AGENTS.md`, `docs/agents/`, backend
README)
- [x] Rule IDs covered or changed: none
- [x] User-facing messages: none
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