Skip to content

API docs consolidation - #38057

Draft
kaapstorm wants to merge 12 commits into
nh/api-openapi-servingfrom
nh/api-docs-consolidation
Draft

API docs consolidation#38057
kaapstorm wants to merge 12 commits into
nh/api-openapi-servingfrom
nh/api-docs-consolidation

Conversation

@kaapstorm

@kaapstorm kaapstorm commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Technical Summary

Migrates API docs from reStructuredText documentation into Tastypie Resource classes.

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

@dimagimon dimagimon added dependencies Pull requests that update a dependency file Risk: High Change affects files that have been flagged as high risk. Risk: Medium Change affects files that have been flagged as medium risk. labels Aug 21, 2026
@kaapstorm
kaapstorm force-pushed the nh/api-docs-consolidation branch from d24e49b to bb13a9c Compare August 21, 2026 18:28
must ``copy.deepcopy`` it first.
"""
path = spec_path(slug)
if not path.exists():

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

path is determined by slug which is not a user-provided value. It is based on the name and version of an API and set by a developer.

path = spec_path(slug)
if not path.exists():
return None
return json.loads(path.read_text())
def read_page(slug):
"""The built Redoc page for ``slug``, or None if the build has not run."""
path = page_path(slug)
if not path.exists():
path = page_path(slug)
if not path.exists():
return None
return path.read_text()
Comment thread corehq/apps/api/openapi/artifacts.py Fixed
Comment thread corehq/apps/api/openapi/artifacts.py Fixed
@kaapstorm
kaapstorm force-pushed the nh/api-docs-consolidation branch 2 times, most recently from d3d5439 to a7dbdcd Compare August 27, 2026 11:04
Base automatically changed from nh/api-test-isolation-fixes to master August 31, 2026 14:17
Authentication, URL structure, versioning, pagination and throttling were
repeated in the preamble of most per-API pages, with authentication
deferred to a Confluence link from every one of them. State each once.
Auditing list-mobile-workers.rst and mobile-worker.rst against the
generated spec surfaced several constraints that were only ever
written down in the hand-authored RST, not in the OpenAPI output:
phone_numbers/groups/locations are fully replaced (not merged) on
update, primary_location and locations must be provided together
(and both empty clears them), send_confirmation_email_now on update
requires an unconfirmed account with an email, user_data omits
digit-leading keys under XML, and username is required to create a
mobile worker. Added these to the resource's Docs.field_schemas and
regenerated the spec so the upcoming page reduction doesn't drop them.
The RST reduction sweep records, per source page, where every claim it made
ended up -- in a spec, in the guide, or judged obsolete. That checklist is
process record-keeping rather than published CommCare documentation, and the
pages are in no toctree, so the build would otherwise report each one as
unreferenced. The first checklist arrives with the next commit.
Both pages are now a short orientation plus a link to the generated
/api/docs/user-v1/ reference, each with its own orientation sentence
rather than cross-referencing the other page. Added a "Response
format" note to the guide (index.rst) for the format=xml/json query
parameter, which several pages document individually. The per-item
sweep checklist recording where every claim went (spec, guide,
obsolete) is at docs/api/sweep/user-v1.md.
name is required and must be unique per domain, users is fully
replaced on PUT, and metadata is replaced wholesale rather than
merged. These constraints were only in user-group.rst prose; add them
to GroupResource's field_schemas so they survive that page's reduction.
Both pages now give a short orientation and link directly to
/api/docs/group-v1/, rather than one page cross-referencing the
other. Every constraint from the prose is accounted for in
docs/api/sweep/group-v1.md: in the regenerated spec, in the
docs/api/index.rst guide, or (path field) obsolete.
Most field and parameter descriptions for form-v1 were already written
into the resource in an earlier commit on this branch; this sweep
re-verifies that work against the two RST pages and finds one gap (the
limit parameter's maximum) plus the form-data-specific items.

The Form Attachments section of form-data.rst documents
get_form_attachment_response, a plain Django view with no OpenAPI spec,
so it is kept byte-for-byte identical rather than reduced -- it is the
only documentation that endpoint has.
The list/detail parameter and field descriptions were already promoted
into corehq/apps/api/resources/v0_4.py by an earlier commit on this
branch, so this sweep is mostly verification: it finds several stale
claims (a username/user_name field that no longer exists, a top-level
version field cases never had, a "Forms Associated" shape that doesn't
match the real xforms_by_name/xforms_by_xmlns response, a referrals
feature removed from the product long ago, and never-implemented
properties=/indices= toggles) and removes them rather than carrying
them forward.
Add field descriptions to LocationResource (v0_6) covering behavior the
locations-v2.rst sweep needs to verify: location_data is fully replaced
(not merged) on write, site_code auto-generation, name/site_code
uniqueness, parent_location_id and location_type_code cross-field
validation on create/update, location_id's role in bulk PATCH, and the
bulk PATCH endpoint's atomicity.
Task 8 of the API docs consolidation sweep. Reduces locations-v1.rst,
locations-v2.rst and location-types.rst (419 lines total) to a title,
orientation sentence, and a link to the generated OpenAPI reference,
now that every field and endpoint fact is documented in the resources'
Docs/help_text and covered by the reference pages at /api/docs/.

Combined sweep checklist at docs/api/sweep/location.md rather than
three separate files: all three pages are served by the same
locations/resources module family and their prose overlaps heavily, so
classifying shared items once and applying them across all three pages
avoided repeating the same reasoning three times.
Twelve constraints move from prose into the specs, several of them
conditionals the prose stated unconditionally: fields is not required on
create (it defaults to no fields), a lookup table's tag is required and
immutable while every other field is independently optional, sort_key is
server-assigned on create whatever the client sends, and a row PUT with
neither fields nor item_attributes persists nothing.

FixtureResource also declares its allowed methods explicitly. The class
defines no obj_create/obj_update/obj_delete, so a write previously raised
NotImplementedError and answered 500; restricting Meta to GET makes that a
correct 405 without removing any working functionality.
fixture.rst covered three specs, so the reduced page carries three links.
The fixture-v1 and fixapi bulk-upload sections have no spec slug at all
and are recorded as out of scope rather than reduced, in the per-item
sweep checklist at docs/api/sweep/fixture.md.
@kaapstorm
kaapstorm force-pushed the nh/api-docs-consolidation branch from a7dbdcd to afbefbc Compare August 31, 2026 21:26
@cache_hits_only
def spec_content_hash(slug):
path = spec_path(slug)
if not path.exists():
path = spec_path(slug)
if not path.exists():
return None
return hashlib.sha256(path.read_bytes()).hexdigest()
@kaapstorm
kaapstorm changed the base branch from master to nh/api-openapi-serving September 1, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file Risk: High Change affects files that have been flagged as high risk. Risk: Medium Change affects files that have been flagged as medium risk.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants