The sync app includes a small HTTP client for SyNCH's CCMDD API in synch/ccmdd.py
The client only supports these CCMDD endpoints:
POST /wapi/prescriptionLimitedPOST /wapi/patientLimitedGET /wapi/facility
For the limited prescription and patient endpoints, the only supported filter is the
optional date_updated field. The patient endpoint also supports
prescription_date_updated.
Instantiate the client with the CCMDD base URL and digest-auth credentials:
from synch.ccmdd import CCMDDAPIClient
client = CCMDDAPIClient(
base_url="https://test.ccmdd.org.za",
username="api-user",
password="secret",
)Fetch updated prescriptions, patients, or all facilities:
from datetime import datetime
for prescription in client.iter_limited_prescriptions():
...
for patient in client.iter_limited_patients(
date_updated=datetime(2024, 1, 2, 3, 4, 5),
):
...
for patient in client.iter_limited_patients(
prescription_date_updated=datetime(2024, 1, 2, 3, 4, 5),
):
...
for facility in client.iter_facilities():
...The methods return iterators of raw item dictionaries from the CCMDD API response.
date_updated is optional for the limited prescription and patient methods.
prescription_date_updated is optional for the limited patient method.
- If omitted, the request body is empty.
- If provided, it is formatted as
YYYY-MM-DD HH:MM:SS.SSSSSS. - Only one patient filter may be sent per
iter_limited_patients()request.
The client handles the CCMDD long-running operation flow automatically.
- For
202 Acceptedresponses, it follows the returnedstatus_locationuntil the operation succeeds. - It treats the API
resultfield as an integer code from the wire format:1immediate,2long-running,3multi long-running. - It waits 5 minutes between each poll of the status endpoint.
- It gives up after 12 status polls, which is a 1 hour wait budget.
- Temporary retries due to failures while polling do not count against the 12 poll limit.
- Once the status is
succeeded, it fetches the final data fromresource_location. - Multi-operation patient responses are fetched and flattened into one iterator.
The client retries temporary failures up to 5 times with random exponential backoff.
- Each HTTP request uses a 60 second timeout before it is retried or fails.
- Retryable
4xxstatuses:408,409,425,429 - Retryable
5xxstatuses: all500,502,503,504 - Retryable transport failures:
requestsexceptions such as timeouts and connection errors - Responses that return
200but cannot be decoded as JSON are retried as temporary failures - If JSON retries are exhausted, the raw response body is included in the failure message and remains available in the failure context for Sentry
Non-temporary failures raise an exception immediately.
The client raises CCMDDAPIError subclasses for caller-visible failures:
CCMDDRetryExhausted: the request kept failing with temporary errors until the retry limit was exceededCCMDDLongRunningOperationTimeout: the operation status did not reachsucceededwithin 12 polls