API & Backend

Bypassing Third-Party Rate Limits: Designing Resilient API Middleware with Redis and Edge Functions

By Laurince QuijanoJuly 13, 20267 min read
Bypassing Third-Party Rate Limits: Designing Resilient API Middleware with Redis and Edge Functions

When building modern web applications, integrating external SaaS APIs (such as CRM dashboards, weather feeds, payment gateways, or currency indexes) is extremely common.

However, query costs can scale quickly. Direct-to-client integrations and high-frequency backend calls can trigger rate limits (HTTP 429 Too Many Requests), lead to expensive API usage billing overages, and degrade frontend loading performance.

To solve this, developers can implement a serverless caching middleware layer at the edge using Redis and Edge Functions. This pattern intercepts incoming queries, queries a serverless Redis cluster first, and returns cached payloads in under 10ms.

Here is the architectural blueprint and code implementation to build a resilient, cached API middleware.

---

The API Caching Architecture Blueprint

In this configuration, we place a serverless edge handler (deployed on global CDN edge nodes) between our clients and the external API: 1. Client Request: The client requests data from our internal API endpoint (e.g., /api/feed). 2. Edge Middleware: An edge function intercepts the request, generates a cache key, and queries a serverless Redis cluster (such as Upstash Redis). 3. Cache Hit: If the key exists in Redis, the edge function immediately returns the payload to the client. Speed: <10 ms. 4. Cache Miss: If the key is expired or missing, the edge function fetches the fresh payload from the third-party API, writes it to Redis with an explicit Time-To-Live (TTL), and returns it to the client.

This caching pattern protects the source API key, prevents rate limit exhaustion, and maintains sub-second loads for users globally.

---

Step-by-Step Implementation

1. Installing Serverless Redis Client We use Upstash's HTTP-based serverless Redis client (@upstash/redis), which is designed specifically to run in restricted edge environments (like Vercel Edge Functions or Cloudflare Workers) since it connects via REST rather than persistent TCP sockets.

2. Writing the Edge Cache Handler Next, we construct the Next.js API route handler to intercept requests and manage cache keys:

import { Redis } from "@upstash/redis";

// Initialize the serverless Redis client const redis = new Redis({ url: process.env.UPSTASH_REDIS_REST_URL || "", token: process.env.UPSTASH_REDIS_REST_TOKEN || "", });

const CACHE_KEY = "global_api_feed_cache"; const CACHE_TTL = 300; // Cache duration: 5 minutes (300 seconds)

export async function GET(request: Request) { try { // 1. Attempt to fetch payload from Redis cache const cachedPayload = await redis.get(CACHE_KEY);

if (cachedPayload) { return NextResponse.json(cachedPayload, { headers: { "X-Cache-Status": "HIT", "Content-Type": "application/json", }, }); }

// 2. Cache Miss: Query the third-party API const response = await fetch("https://api.third-party-service.com/v2/feed", { headers: { "Authorization": Bearer ${process.env.THIRD_PARTY_API_KEY}, }, });

if (!response.ok) { throw new Error("External API responded with an error"); }

const freshData = await response.json();

// 3. Store fresh data in Redis with a TTL (expiration) await redis.set(CACHE_KEY, freshData, { ex: CACHE_TTL });

return NextResponse.json(freshData, { headers: { "X-Cache-Status": "MISS", "Content-Type": "application/json", }, }); } catch (error) { console.error("API Cache Error:", error); // Fallback: If Redis is down, fetch directly to avoid site crash return NextResponse.json( { error: "Failed to retrieve feed data" }, { status: 500 } ); } }

---

Advanced Caching Strategy: Stale-While-Revalidate

For mission-critical data feeds, a hard cache miss can still delay the page paint for the unfortunate user who triggers it. In this scenario, we can implement Stale-While-Revalidate:

  1. Retrieve Cache: When a client requests data, the edge function fetches the cached payload even if its TTL has expired (meaning it is "stale").
  2. Instant Return: The stale data is returned to the visitor instantly.
  3. Asynchronous Refresh: In the background, the edge function executes a non-blocking fetch to get fresh data from the third-party API and updates the Redis cache.

This guarantees 100% of visitors get sub-second page loads, while background workers keep the catalog data updated.

---

Key Benefits of Edge API Caching

Drastic Cost Savings: If you call an API that charges $0.001 per query, caching it for 5 minutes under high traffic (e.g., 100,000 daily hits) slashes API execution calls down to just 288 runs per day—reducing API bills by 99.7%*. Global Performance*: Edge functions execute on nodes physically closest to the client, delivering payload data instantly. Resiliency*: If the third-party API goes down, the edge function can fall back to serving the last cached payload, ensuring your site remains online and operational.

Need premium developer consulting?

Let's discuss how we can build API split checkouts, dynamic Next.js interfaces, or speed audits for your business.

Get in Touch