DocsRate Limiting

Rate Limiting

PortalData menerapkan rate limiting untuk memastikan stabilitas dan keadilan penggunaan API. Pelajari batas request berdasarkan tier langganan Anda.

Cara Kerja Rate Limiting

Rate limiting diterapkan menggunakan algoritma sliding window untuk memberikan pengalaman yang lebih baik dibanding fixed window. Setiap API key memiliki batas berdasarkan tier langganan perusahaan.

Jenis Pembatasan

Per MenitBatas request per menit untuk mencegah burst traffic
Per BulanKuota total request per bulan sesuai tier langganan

Batas Request per Tier

Setiap tier memiliki batas request yang berbeda:

TierRequest/MenitRequest/HariRequest/BulanBurst Allowance
Free101001.00020
Starter1002.00050.000200
Growth50020.000500.0001.000
Enterprise2.000100.000Unlimited5.000

Apa itu Burst Allowance?

Burst allowance memungkinkan Anda mengirim request lebih dari batas per menit untuk waktu singkat. Ini berguna untuk skenario batch processing atau initial data fetch.

Response Headers

Setiap response API menyertakan headers yang menunjukkan status rate limit Anda:

HeaderDeskripsiContoh
X-RateLimit-LimitBatas request per menit untuk tier Anda100
X-RateLimit-RemainingSisa request yang tersedia di window saat ini95
X-RateLimit-ResetUnix timestamp kapan limit akan reset1706054460
X-RateLimit-PolicyKebijakan rate limit (limit;window)100;w=60
Retry-AfterDetik menunggu sebelum retry (hanya saat 429)30

Contoh Response Headers

HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1706054460
X-RateLimit-Policy: 100;w=60

Ketika Limit Terlampaui

Saat rate limit terlampaui, API akan mengembalikan HTTP status 429:

429 Too Many Requests - Rate Limit
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Upgrade your plan for higher limits.",
  "retry_after": 30,
  "upgrade_url": "https://portaldata.id/pricing"
}
429 Too Many Requests - Monthly Limit
{
  "error": "monthly_limit_exceeded",
  "message": "Monthly request limit of 1000 exceeded. Please upgrade your plan."
}

Handling Rate Limits

Contoh kode untuk menangani rate limiting dengan baik:

JavaScript - Exponential Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, {
        ...options,
        headers: {
          'X-API-Key': process.env.PORTALDATA_API_KEY,
          ...options.headers
        }
      });

      // Jika rate limited, tunggu dan retry
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After') || '30');
        console.log(`Rate limited. Waiting ${retryAfter}s before retry...`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      // Log rate limit info untuk monitoring
      const remaining = response.headers.get('X-RateLimit-Remaining');
      if (remaining && parseInt(remaining) < 10) {
        console.warn(`Low rate limit remaining: ${remaining}`);
      }

      return response;
    } catch (error) {
      lastError = error;
      // Exponential backoff untuk network errors
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError;
}
Python - Rate Limit Aware Client
import time
import requests
from functools import wraps

class PortalDataClient:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = 'https://api.portaldata.id/api/v1'
        self.session = requests.Session()
        self.session.headers['X-API-Key'] = api_key

    def _request(self, method, endpoint, **kwargs):
        url = f'{self.base_url}{endpoint}'
        max_retries = 3

        for attempt in range(max_retries):
            response = self.session.request(method, url, **kwargs)

            # Track rate limit
            remaining = response.headers.get('X-RateLimit-Remaining')
            if remaining:
                print(f'Rate limit remaining: {remaining}')

            # Handle rate limit
            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 30))
                print(f'Rate limited. Waiting {retry_after}s...')
                time.sleep(retry_after)
                continue

            return response

        raise Exception('Max retries exceeded')

    def get_regions(self, **params):
        return self._request('GET', '/regions', params=params).json()

    def get_kbli(self, code):
        return self._request('GET', f'/kbli/{code}').json()

# Penggunaan
client = PortalDataClient(api_key='pk_live_xxx')
regions = client.get_regions(level='province')

Best Practices

Implementasi Caching

Cache response untuk data yang jarang berubah (seperti wilayah, KBLI). Ini mengurangi jumlah request dan mempercepat aplikasi.

Monitor Rate Limit Headers

Pantau header X-RateLimit-Remaining dan beri peringatan jika mendekati limit. Ini membantu mencegah gangguan layanan.

Gunakan Exponential Backoff

Saat mendapat error 429, jangan langsung retry. Gunakan exponential backoff atau nilai dari header Retry-After.

Batch Requests Jika Memungkinkan

Gabungkan beberapa request menjadi satu jika API mendukung. Misalnya, gunakan include=children daripada request terpisah.

Butuh Limit Lebih Tinggi?

Jika aplikasi Anda membutuhkan limit yang lebih tinggi, pertimbangkan untuk upgrade tier:

Lihat Juga