Skip to main content

Offline Content Cache Patterns

Content Sync works best when your app treats the server as the source of truth and the local database as a readable cache.

The UI reads from local storage. The sync engine updates that storage in the background.

Local Tables

Use separate tables for sync state and cached rows.

interface ContentSyncToken {
resourcesFilter: string;
syncToken: string;
updatedAt: string;
}

interface ContentCacheRow {
resourceGroup: string;
resourceId: number;
recordType: string;
recordKey: string;
payload: Record<string, unknown>;
updatedAt: string;
}

Use a unique key on:

resourceGroup + resourceId + recordType + recordKey

That makes ROW_CREATE and ROW_UPDATE safe to apply more than once.

Background Refresh

Recommended triggers:

TriggerSuggested action
App install or first openBootstrap only the resources the app needs.
App launchRun incremental sync in the background.
Network restoredRun incremental sync.
Reader opens a resourceUse local content immediately, then refresh in the background.
Token rejectedRe-bootstrap that resource filter.

Replacing a Resource

When a change includes snapshot_url, fetch the full copy and replace rows in one transaction.

When snapshot_url is present and non-null, we return a relative /api/v4/... path like /api/v4/resources/snapshots/translations/19. You should prefix that path with https://apis.quran.foundation/content.

This prevents mixed old and new rows from appearing in the reader UI.

Practical Defaults

DecisionDefault
Page sizeUse per_page=100 unless your client needs smaller pages.
Token storageStore per resource filter, not globally.
Applying changesMake every apply operation idempotent.
Failed syncKeep the old token and retry later.
Failed full copy fetchDo not store the new sync token until the required full copy succeeds.

What Not To Do

  • Do not construct cursors manually. Use next_page_url.
  • Do not treat next_page_url or snapshot_url as an absolute URL.
  • Do not store next_sync_token before all pages and required full copies are applied.
  • Do not reuse a token with a different resources filter.
  • Do not treat RESOURCE_UPDATE as an instruction to delete or refetch rows.