Skip to content

UN-3770 [MISC] Follow DRF pagination on all clone list endpoints#24

Draft
chandrasekharan-zipstack wants to merge 1 commit into
mainfrom
feat/paginate-list-helpers
Draft

UN-3770 [MISC] Follow DRF pagination on all clone list endpoints#24
chandrasekharan-zipstack wants to merge 1 commit into
mainfrom
feat/paginate-list-helpers

Conversation

@chandrasekharan-zipstack

Copy link
Copy Markdown
Contributor

What & why

Part of the UN-3770 list-pagination workstream. This is step 1 of 4 and is the prerequisite for flipping the OSS list endpoints to unconditional pagination — it must be merged and released before that lands.

Every list_* helper in PlatformClient already unwrapped a paginated envelope:

return result if isinstance(result, list) else result.get("results", [])

…but none of them ever sent ?page or followed next. They read page one and stopped.

That is already a live bug, not a future one. tags/, pipeline/ and api/deployment/ use CustomPagination on the backend today, so cloning an org with more than 50 tags / pipelines / API deployments silently drops the rest — no error, no warning. The stale comment on list_adapters ("no pagination on this endpoint") is the assumption that made this easy to miss.

Once unstract#2187's follow-up makes adapters, connectors, workflows and prompt-studio unconditionally paginated, the same truncation hits those too. Silent partial data loss is a far worse failure mode than a hard break, so the client has to be fixed first.

Approach

PlatformClient._paginate(path, params):

  • Bare list → returned unchanged. No server-version negotiation, no feature flag. The same client works against an old on-prem deployment that doesn't paginate and a new one that does, so this ships and releases entirely independently of the backend work.
  • Envelope → walks next to exhaustion.
  • Refuses to return a short read. Collected rows are checked against the reported count; a mismatch raises PlatformAPIError. This is the durable protection — any future truncation becomes loud instead of silent.
  • Cyclic next raises rather than hanging a migration forever.

_request() is split into a URL-building wrapper over _send(), because DRF's next links are absolute and can't go through org-relative path composition. _request()'s signature is unchanged, so every existing caller is untouched.

All 23 list helpers now route through _paginate. list_lookup_versions deliberately keeps its bespoke unwrap — that endpoint returns {"versions": [...], "next_version_number"}, not a DRF envelope.

Testing

  • tests/clone/test_client.py: 3 new tests — follows next across pages and hits the absolute URL verbatim; raises on a short read; raises on a cyclic next. The two pre-existing tests pinning bare-list and single-page-envelope behaviour still pass unchanged, which is the backward-compatibility guarantee.
  • Full suite: 250 passed.
  • ruff check + ruff format clean.
  • ⚠️ Live validation still pending — hence draft. tags/ already paginates in staging, so list_tags exercises the real envelope → nextcount path end-to-end with no backend change required.

Residual risk

A customer pinned to an older client version still truncates silently after the backend flip; nothing here helps them retroactively. Tracked in the rollout plan, along with the option of instrumenting bare-array responses for one release to measure who is still affected before anything breaks.

🤖 Generated with Claude Code

https://claude.ai/code/session_018HXYFVCZGi7YN9qjDGyJCQ

Every list_* helper unwrapped a paginated envelope but never sent ?page
and never followed `next` — it read page one and stopped. Endpoints that
already paginate (tags/, pipeline/, api/deployment/) have therefore been
silently truncating at 50 rows, and the same would hit adapters,
connectors and prompt-studio once UN-3770 makes their pagination
unconditional. A clone that copies a subset without erroring is worse
than one that fails.

Add PlatformClient._paginate(), which short-circuits on a bare list so
the client keeps working against deployments where an endpoint is not
paginated, otherwise walks `next` to exhaustion. It refuses to return a
short read: the collected row count is checked against the reported
count, and a cyclic `next` raises instead of looping forever.

_request() is split so the absolute `next` URLs DRF emits can be issued
without going through org-relative path composition. Its signature is
unchanged, so every existing caller is untouched.

All 23 list helpers now route through it. list_lookup_versions keeps its
bespoke unwrap — that endpoint returns {"versions": [...]}, not a DRF
envelope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HXYFVCZGi7YN9qjDGyJCQ
@chandrasekharan-zipstack chandrasekharan-zipstack changed the title [FIX] Follow DRF pagination on all clone list endpoints UN-3770 [MISC] Follow DRF pagination on all clone list endpoints Jul 24, 2026
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