Skip to content
FrontHeaven
Light mode
Level 2 — IntermediateIntermediate 40 min read

API Architecture: Webhooks, Rate Limiting & REST Endpoints

Master enterprise API architecture in Next.js: cryptographic webhook signature verification (Stripe), Redis-backed rate limiting (@upstash/ratelimit), standardized error envelopes, and API versioning.

Next.js progress0%

API Architecture: Webhooks, Rate Limiting & REST Endpoints

While Server Actions power internal frontend UI mutations, enterprise systems still require robust Route Handlers (route.ts) for mobile client consumption, public partner APIs, rate-limited public search endpoints, and cryptographic Webhook Receivers (e.g. Stripe checkout fulfillments).

In this lesson, you will master API rate limiting with Redis, cryptographic webhook verification, standardized JSON response envelopes, and versioning patterns.

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    Enterprise Route Handler Pipeline                        │
├─────────────────────────────────────────────────────────────────────────────┤
│  Incoming Request                                                           │
│         │                                                                   │
│         ├── 1. Rate Limiter Guard (Redis Token Bucket) ──> (429 Too Many)   │
│         ├── 2. API Key / Signature Verification        ──> (401 / 403)      │
│         ├── 3. Zod Payload Schema Validation           ──> (400 Bad Request)│
│         ├── 4. Business Logic / Database Mutation                           │
│         └── 5. Standardized JSON Envelope Response     ──> (200 OK)         │
└─────────────────────────────────────────────────────────────────────────────┘

1. Rate Limiting with Upstash Redis

Protect public Route Handlers against brute force attacks and denial-of-service (DoS) using token-bucket rate limiting:

TypeScript
// app/api/search/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(20, '10 s'), // Max 20 requests per 10 seconds
});

export async function GET(req: NextRequest) {
  const ip = req.ip ?? '127.0.0.1';
  const { success, limit, remaining } = await ratelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: 'Too Many Requests', limit, remaining },
      { status: 429 }
    );
  }

  return NextResponse.json({ success: true, results: [] });
}

2. Cryptographic Webhook Receivers (Stripe Example)

Webhooks receive asynchronous payment notifications. You must verify the raw cryptographic signature before fulfilling orders:

TypeScript
// app/api/webhooks/stripe/route.ts
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-06-20',
});

export async function POST(req: Request) {
  const body = await req.text(); // Raw text required for signature verification!
  const headerList = await headers();
  const signature = headerList.get('stripe-signature');

  if (!signature) {
    return NextResponse.json({ error: 'Missing stripe signature' }, { status: 400 });
  }

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      body,
      signature,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err: any) {
    return NextResponse.json({ error: `Webhook Error: ${err.message}` }, { status: 400 });
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object as Stripe.Checkout.Session;
    // Fulfill customer purchase in database
    console.log(`Payment confirmed for session: ${session.id}`);
  }

  return NextResponse.json({ received: true });
}

Summary & Key Takeaways

  • Public endpoints should be protected with rate limiting (@upstash/ratelimit).
  • Webhook handlers require parsing the raw text body (await req.text()) to verify cryptographic HMAC signatures.
  • Standardized response envelopes ({ success, data, error }) maintain consistent client integration contracts.

Best Practices & Senior Guidance

  1. Disable Body Parsing for Webhooks: Always read req.text() rather than req.json() when verifying HMAC signatures; whitespace modifications in parsed JSON break cryptographic signatures.
  2. Return Fast 200 OK on Webhooks: Acknowledge webhooks immediately and offload heavy background tasks (like email dispatch or PDF rendering) to asynchronous background job queues.

Finished studying? Lock it in.

Mark this lesson as completed to track your journey.