DEV Community

Kiell Tampubolon
Kiell Tampubolon

Posted on

Cara Bypass Rate Limit API Secara Etis Pakai Local Proxy

Cara Bypass Rate Limit API Secara Etis Pakai Local Proxy

Cerita di balik masalah

Kamu sedang menyambungkan automation ke sebuah API. Script jalan lancar lima menit pertama, lalu mulai muntah 429. Kamu tambah delay, tetap kena. Kamu bagi proses jadi beberapa worker, kena lagi.

Rate limit itu bukan musuh. Itu cara penyedia API melindungi infrastrukturnya dan menjaga kualitas layanan untuk semua orang. Masalahnya, banyak client menulis ulang logika penanganan limit yang sama di setiap project: retry di sini, sleep di sana, dan satu worker nakal yang merusak semuanya.

Solusi yang rapi: taruh satu komponen di tengah, yaitu local proxy. Semua request dari aplikasimu lewat proxy ini, dan proxy yang menangani rate limit secara terpusat.

Kapan kita butuh proxy lokal

Tiga situasi di mana proxy lokal masuk akal:

  1. Retry backoff. Kamu tidak mau setiap service punya logika retry sendiri. Satu tempat, satu kebijakan.
  2. Queueing. Saat limit hampir habis, request antre dulu, bukan langsung gagal.
  3. Multi endpoint pooling. Kalau penyedia API memberi beberapa key atau endpoint, proxy bisa memutar beban antar keduanya. Catatan penting: rotasi key untuk menghindari limit adalah pelanggaran ToS di banyak layanan. Gunakan pooling hanya kalau ToS mengizinkan, misalnya beberapa akun organisasi yang memang sah.

Arsitekturnya sederhana

Diagram arsitektur client ke local proxy ke upstream API

Client hanya tahu satu alamat: proxy. Proxy yang tahu kapan harus menahan, kapan harus mencoba ulang, dan kapan boleh langsung lewat.

Implementasi minimal dengan Python

Ini versi kecil pakai FastAPI dan httpx, sekitar 60 baris:

import asyncio, time
import httpx
from fastapi import FastAPI, Request, Response

UPSTREAM = "https://api.example.com"
RATE = 5          # request per detik
_app = FastAPI()
_bucket_last = 0.0
_lock = asyncio.Lock()

async def acquire():
    global _bucket_last
    async with _lock:
        now = time.monotonic()
        wait = (1 / RATE) - (now - _bucket_last)
        if wait > 0:
            await asyncio.sleep(wait)
        _bucket_last = time.monotonic()

@_app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(path: str, request: Request):
    await acquire()
    async with httpx.AsyncClient(base_url=UPSTREAM, timeout=30) as c:
        r = await c.request(
            request.method, f"/{path}",
            content=await request.body(),
            headers={k: v for k, v in request.headers.items()
                     if k.lower() not in ("host", "content-length")},
            params=request.query_params,
        )
    if r.status_code == 429:
        retry_after = float(r.headers.get("retry-after", "2"))
        await asyncio.sleep(retry_after)
        return await proxy(path, request)   # retry sekali lagi
    return Response(content=r.content, status_code=r.status_code,
                    headers=dict(r.headers))
Enter fullscreen mode Exit fullscreen mode

Jalankan dengan uvicorn proxy:app --port 8080, lalu arahkan semua client ke http://localhost:8080. Selesai. Logika limit kini hidup di satu tempat.

Versi Node.js juga ringkas, tapi polanya sama: middleware yang menghitung token, queue yang menahan request, dan retry yang menghormati header Retry-After.

Tips etis

Bagian paling penting dari artikel ini. Proxy lokal adalah alat untuk jadi client yang lebih baik, bukan untuk lolos dari aturan.

  1. Hormati ToS. Baca ketentuan layanan sebelum membangun apa pun. Kalau ToS melarang rotasi akun atau key, jangan lakukan. Kalau melarang scraping, jangan scraping.
  2. Hormati Retry-After. Kalau server memberi tahu kapan boleh mencoba lagi, patuhi angkanya. Jangan paksa.
  3. Cache respons. Rate limit paling murah adalah yang tidak perlu dikirim. Cache GET dengan TTL wajar, invalidasi saat ada write.
  4. Exponential backoff dengan jitter. Jangan retry semua worker di detik yang sama. Tambahkan noise acak supaya tidak terjadi thundering herd.
  5. Circuit breaker. Kalau upstream terus gagal, berhenti menghantam. Tandai circuit terbuka selama beberapa detik, lempar error yang jujur ke caller, lalu coba lagi pelan-pelan.
  6. Pantau konsumsi limitmu sendiri. Banyak API mengembalikan sisa kuota di header (X-RateLimit-Remaining dan teman-temannya). Simpan nilai itu di proxy dan perlambat sebelum 429 datang, bukan sesudah.

Penutup

Rate limit bukan teka-teki untuk dipecahkan dengan trik. Ia sinyal dari server soal ritme yang wajar. Local proxy membuat codebase-mu mengikuti ritme itu secara otomatis: satu tempat untuk throttle, retry, dan cache, tanpa menyebar logika ke tiap service.

Bangun dia untuk menjadi tetangga yang baik di internet. API-mu, dan tim SRE penyedia layanannya, akan berterima kasih.

Top comments (0)