Skip to content

Set Case API v2 Descriptions - #38102

Draft
kaapstorm wants to merge 5 commits into
nh/api-docs-consolidationfrom
nh/case-v2-descriptions-rebased
Draft

Set Case API v2 Descriptions#38102
kaapstorm wants to merge 5 commits into
nh/api-docs-consolidationfrom
nh/case-v2-descriptions-rebased

Conversation

@kaapstorm

@kaapstorm kaapstorm commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Technical Summary

Adds descriptions for the Case API v2 view.

Feature Flag

Safety Assurance

Safety story

Automated test coverage

QA Plan

Migrations

  • The migrations in this code can be safely applied first independently of the code. Pay particular attention to backward incompatible operations like RemoveField, RenameField, RemoveConstraint, and others described here that can cause errors when migrations are applied to a live database.

Rollback instructions

  • This PR can be reverted after deploy with no further considerations

Labels & Review

  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

Nineteen of twenty response fields carried no description on the most
heavily used API in the catalogue. The detail response is an anyOf, which
the old RST renderer showed only the first branch of, so even what little
was described was partly unpublished.

Two schema corrections came out of writing them. The bulk-fetch response
never declared matching_records or missing_records, though get_bulk()
returns both -- a spec that was wrong about the API, not merely quiet.
And the bulk error stub returns case_id/external_id alongside error,
which the schema did not say.

date_closed's behaviour after a reopen is marked for domain review in
docs/api/sweep/case-v2.md rather than guessed at.
Every other documented API derives its response schema from tastypie's
metadata, so a field cannot appear in one and not the other. Case v2 has no
metadata to derive from: serialize_case() is a dict literal and the schema is
a second dict literal written to match it, with nothing keeping the two in
agreement.

That is not a hypothetical risk. The bulk-fetch response omitted
matching_records and missing_records for as long as it was documented, and
the omission was found by reading get_bulk() rather than by anything failing
-- which is the failure mode this test removes.

Checks both directions, because each catches a different mistake: a field
the API returns but the spec never mentions leaves an integrator unable to
rely on it, and a field the spec promises but the API never returns makes a
generated client wait for something that never arrives.

serialize_es_case() serves the list and bulk-fetch responses while
serialize_case() serves the detail and write responses; one schema can
describe both because TestAPISerialization already pins the two to each
other, so this test follows serialize_case() alone.
Constraints that had no home in the spec, found while reading the
create/update/upsert distinctions closely against the code:

- PUT to the case detail URL does not check a body-supplied case_id against
  the one in the URL -- the body's value silently wins. The external-ID PUT
  endpoint does check, so the two endpoints disagree, and only one of them
  says so. Documented on the case_id path parameter.
- The bulk-upsert duplicate-creation danger and its race condition.
- The bulk item cap stated in prose, not only as maxItems.
- The bulk error message is always "not found", which keeps a client from
  telling a missing case apart from one in another domain or one it lacks
  permission for.

These were previously carried only by docs/api/cases-v2.rst, which the next
commit reduces; they are published first so nothing is lost in between.
docs/api/cases-v2.rst (711 lines) is reduced to a title, orientation
paragraph and a link to /api/docs/case-v2/, per the sweep procedure.
docs/api/sweep/case-v2.md records every claim's disposition.

Several claims on the old page were corrected against the code rather than
carried forward as written: indices being "not included by default" (it
always is); the property-name rule being narrower in prose than the actual
XML-identifier check; the create/update response field being "xform_id" (it
is "form_id"); the bulk-submission-limit error text ("Payload too large" vs
the real message); and the external-ID GET warning that a non-unique match
"will return one case" (it now raises a 400 listing every match instead).

The constraints that had no home in the spec were published by the previous
commit before being deleted from the page here.

date_closed's reopened-case behavior is recorded in the checklist as needing
domain review.
The product owner confirmed the reading the code suggested: this API
cannot reopen a case, and the way to reopen one is to archive the form
that closed it. Both closed and date_closed now say so, since an
integrator would otherwise discover it by experiment -- close: true works,
close: false silently does nothing.

Clears the one needs-domain-review row in the case-v2 sweep checklist.
@dimagimon dimagimon added the Risk: High Change affects files that have been flagged as high risk. label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Risk: High Change affects files that have been flagged as high risk.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants