Skip to main content

Pagination

The SuprSonic API uses cursor-based pagination with HATEOAS links to help you efficiently navigate through large datasets. All list endpoints support pagination with consistent parameters and response formats.

Pagination Parameters

ParameterTypeDefaultDescription
pageinteger1Page number (1-based)
limitinteger20Items per page (1-100)

Example Request

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://www.suprsonic.com/api/v1/articles?page=2&limit=10"

Pagination Response Structure

All paginated responses include metadata and navigation links:
{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "title": "Article Title",
      // ... article data
    }
  ],
  "meta": {
    "pagination": {
      "page": 2,
      "limit": 10,
      "total": 145,
      "totalPages": 15,
      "hasNext": true,
      "hasPrev": true
    },
    "links": {
      "self": "/api/v1/articles?page=2&limit=10",
      "first": "/api/v1/articles?page=1&limit=10",
      "prev": "/api/v1/articles?page=1&limit=10",
      "next": "/api/v1/articles?page=3&limit=10",
      "last": "/api/v1/articles?page=15&limit=10"
    }
  }
}

Pagination Metadata

Pagination Object

FieldTypeDescription
pageintegerCurrent page number
limitintegerItems per page
totalintegerTotal number of items
totalPagesintegerTotal number of pages
hasNextbooleanWhether there’s a next page
hasPrevbooleanWhether there’s a previous page
Navigation links preserve all query parameters from your original request:
LinkDescription
selfCurrent page
firstFirst page
prevPrevious page (if exists)
nextNext page (if exists)
lastLast page

Pagination with Filters

When using filters, pagination links automatically preserve your search parameters:
# Request with filters
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://www.suprsonic.com/api/v1/articles?q=SEO&tags=marketing&status=published&page=1&limit=10"
{
  "success": true,
  "data": [...],
  "meta": {
    "pagination": {...},
    "links": {
      "self": "/api/v1/articles?q=SEO&tags=marketing&status=published&page=1&limit=10",
      "next": "/api/v1/articles?q=SEO&tags=marketing&status=published&page=2&limit=10"
    }
  }
}

Implementation Examples

JavaScript/Node.js

class SuprSonicClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://www.suprsonic.com/api/v1';
  }

  async getAllArticles(filters = {}) {
    let allArticles = [];
    let page = 1;
    let hasMore = true;

    while (hasMore) {
      const response = await this.getArticles({ 
        ...filters, 
        page, 
        limit: 100 
      });
      
      allArticles.push(...response.data);
      hasMore = response.meta.pagination.hasNext;
      page++;
    }

    return allArticles;
  }

  async getArticles(params = {}) {
    const queryString = new URLSearchParams(params).toString();
    const url = `${this.baseUrl}/articles?${queryString}`;
    
    const response = await fetch(url, {
      headers: { 'Authorization': `Bearer ${this.apiKey}` }
    });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }
    
    return await response.json();
  }

  // Iterator pattern for memory efficiency
  async* iterateArticles(filters = {}) {
    let page = 1;
    let hasMore = true;

    while (hasMore) {
      const response = await this.getArticles({ 
        ...filters, 
        page, 
        limit: 50 
      });
      
      for (const article of response.data) {
        yield article;
      }
      
      hasMore = response.meta.pagination.hasNext;
      page++;
    }
  }
}

// Usage examples
const client = new SuprSonicClient('your-api-key');

// Get all articles (automatic pagination)
const allArticles = await client.getAllArticles({ 
  status: 'published' 
});

// Process articles one at a time (memory efficient)
for await (const article of client.iterateArticles({ q: 'SEO' })) {
  console.log(`Processing: ${article.title}`);
}

// Manual pagination with HATEOAS links
let response = await client.getArticles({ limit: 20 });
while (response.meta.pagination.hasNext) {
  // Process current page
  console.log(`Page ${response.meta.pagination.page}: ${response.data.length} articles`);
  
  // Use HATEOAS link for next page
  const nextUrl = response.meta.links.next;
          const nextResponse = await fetch(`https://www.suprsonic.com${nextUrl}`, {
    headers: { 'Authorization': `Bearer ${client.apiKey}` }
  });
  response = await nextResponse.json();
}

Python

import requests
from typing import Generator, Dict, Any, Optional

class SuprSonicClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://www.suprsonic.com/api/v1"
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}"
        })

    def get_articles(self, **params) -> Dict[str, Any]:
        """Get a single page of articles."""
        response = self.session.get(f"{self.base_url}/articles", params=params)
        response.raise_for_status()
        return response.json()

    def iterate_all_articles(self, **filters) -> Generator[Dict[str, Any], None, None]:
        """Iterate through all articles across all pages."""
        page = 1
        while True:
            response = self.get_articles(page=page, limit=100, **filters)
            
            for article in response["data"]:
                yield article
            
            if not response["meta"]["pagination"]["hasNext"]:
                break
            page += 1

    def get_all_articles(self, **filters) -> list[Dict[str, Any]]:
        """Get all articles as a list."""
        return list(self.iterate_all_articles(**filters))

# Usage
client = SuprSonicClient("your-api-key")

# Process articles one by one (memory efficient)
for article in client.iterate_all_articles(status="published"):
    print(f"Processing: {article['title']}")

# Get all articles at once
all_articles = client.get_all_articles(tags="seo,marketing")
print(f"Found {len(all_articles)} articles")

# Manual pagination
response = client.get_articles(limit=20)
print(f"Page {response['meta']['pagination']['page']} of {response['meta']['pagination']['totalPages']}")

Best Practices

1. Use Appropriate Page Sizes

// Good: Reasonable page sizes
const response = await getArticles({ limit: 20 }); // UI pagination
const response = await getArticles({ limit: 100 }); // Bulk processing

// Avoid: Too small (many requests)
const response = await getArticles({ limit: 5 });

// Avoid: Too large (slow responses)
const response = await getArticles({ limit: 1000 });

2. Handle Pagination Errors

async function safePagination(client, filters) {
  const results = [];
  let page = 1;
  const maxRetries = 3;

  while (true) {
    try {
      const response = await client.getArticles({ 
        ...filters, 
        page, 
        limit: 50 
      });
      
      results.push(...response.data);
      
      if (!response.meta.pagination.hasNext) break;
      page++;
      
    } catch (error) {
      if (error.status === 429) {
        // Rate limited - wait and retry
        await new Promise(resolve => setTimeout(resolve, 1000));
        continue;
      }
      throw error;
    }
  }
  
  return results;
}

3. Cache and Store Results

class CachedSuprSonicClient {
  constructor(apiKey, cacheSize = 1000) {
    this.client = new SuprSonicClient(apiKey);
    this.cache = new Map();
    this.cacheSize = cacheSize;
  }

  async getArticles(params = {}) {
    const cacheKey = JSON.stringify(params);
    
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }
    
    const response = await this.client.getArticles(params);
    
    // Simple LRU cache
    if (this.cache.size >= this.cacheSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    
    this.cache.set(cacheKey, response);
    return response;
  }
}

Performance Considerations

  • Optimize page size: Balance between request frequency and response time
  • Use filters: Reduce total items to paginate through
  • Implement caching: Cache responses for frequently accessed pages
  • Monitor rate limits: Implement exponential backoff for rate-limited requests
  • Stream processing: Use iterators for large datasets to avoid memory issues

Common Patterns

Search with Pagination

# Search articles and paginate results
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://www.suprsonic.com/api/v1/articles?q=content+marketing&page=1&limit=25"

Filter by Multiple Tags

# Get articles with specific tags
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://www.suprsonic.com/api/v1/articles?tags=seo,marketing,content&page=1&limit=50"

Status-Based Pagination

# Paginate through draft articles
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://www.suprsonic.com/api/v1/articles?status=draft&page=1&limit=10"