Always paginate. Even if your test environment has 10 users, production might have 10,000. The SDK handles pagination orchestration - use it from day one.
Basic pattern
Every List(), Entitlements(), and Grants() method returns a next page token:
The SDK calls your method repeatedly until you return an empty token. Your job: fetch and convert one page at a time.
Use the API’s next token for termination, not result count. Some APIs return empty pages before the final page, so len(results) < pageSize isn’t reliable. Return "" only when the API signals no more pages.
APIs paginate results differently. Your connector adapts the token to whatever the API expects:
Cursor-based (most modern APIs)
Offset-based (traditional REST)
LDAP paging (Active Directory)
When you have hierarchies, you often need to paginate at multiple levels: “page through orgs, and for each org, page through repos.” The SDK’s pagination.Bag handles this.
How Bag works
The Bag acts as a stack for managing complex pagination state:
Key methods:
Push(state PageState) - Push new pagination state onto stack
Pop() *PageState - Pop current state, make top of stack current
Next(pageToken string) - Update current state with new page token
Current() *PageState - Get current state (may be nil)
Marshal() (string, error) - Serialize state to opaque token
Unmarshal(token string) error - Restore state from token
Example: paginating repos within orgs
Bag.Current() nil safety: The Bag starts empty. Current() returns nil until you Push() a state. Always check for nil before accessing fields.
For deeper hierarchies (org -> team -> members), push and pop states:
Modeling hierarchies
Real systems often have deep hierarchies. The Baton model handles these naturally: declare parent-child relationships and the SDK walks the tree for you.
Two mechanisms connect parent and child
1. Parent declares child types via ChildResourceType annotation:
2. Child references parent via ParentResourceID:
When the SDK calls List() for child resources, it passes the parent’s ResourceId so you can scope your API calls.
Example: GitHub hierarchy
Organization builder:
Repository builder - receives parent org in List():
When to use hierarchies vs flat models
Common hierarchy mistakes
The SDK enforces invariants to catch common bugs:
- Token must progress: Returning the same token you received causes an error. This prevents infinite loops.
- Empty token means done: Return
"" when there are no more pages.
- Consistent page sizes: While not enforced, use consistent page sizes for predictable behavior.
Test with small page sizes (10-20 items) during development to verify pagination works correctly before testing with production-sized datasets.