Orbit API
Guides d’intégration

Next.js sur Vercel

Appeler Orbit depuis une Route Handler sans exposer la clé au navigateur.

L’architecture recommandée est : navigateur → Route Handler Next.js → Orbit API.

Dans Vercel, créez uniquement des variables serveur :

ORBIT_BASE_URL
ORBIT_API_KEY

Ne préfixez jamais la clé avec NEXT_PUBLIC_.

// app/api/interests/search/route.ts
import { NextRequest, NextResponse } from "next/server";

const categories = new Set(["games", "movies", "anime", "series", "music", "books"]);

export async function GET(request: NextRequest) {
  const query = request.nextUrl.searchParams.get("q")?.trim() ?? "";
  const category = request.nextUrl.searchParams.get("category");
  const limit = Number(request.nextUrl.searchParams.get("limit") ?? 20);

  if (!query || query.length > 100) {
    return NextResponse.json({ error: "invalid_query" }, { status: 400 });
  }
  if (category && !categories.has(category)) {
    return NextResponse.json({ error: "invalid_category" }, { status: 400 });
  }
  if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
    return NextResponse.json({ error: "invalid_limit" }, { status: 400 });
  }

  const baseUrl = process.env.ORBIT_BASE_URL;
  const apiKey = process.env.ORBIT_API_KEY;
  if (!baseUrl || !apiKey) {
    return NextResponse.json({ error: "not_configured" }, { status: 503 });
  }

  const orbitUrl = new URL(`${baseUrl}/v1/interests/search`);
  orbitUrl.searchParams.set("q", query);
  orbitUrl.searchParams.set("limit", String(limit));
  if (category) orbitUrl.searchParams.set("category", category);

  const response = await fetch(orbitUrl, {
    headers: { Authorization: `Bearer ${apiKey}` },
    cache: "no-store",
    signal: AbortSignal.timeout(5_000),
  });

  const headers = new Headers({
    "content-type": "application/json",
    "cache-control": "private, no-store",
  });
  for (const name of [
    "x-request-id",
    "x-ratelimit-limit",
    "x-ratelimit-remaining",
    "x-ratelimit-reset",
    "x-orbit-daily-ratelimit-limit",
    "x-orbit-daily-ratelimit-remaining",
    "x-orbit-daily-ratelimit-reset",
    "retry-after",
  ]) {
    const value = response.headers.get(name);
    if (value) headers.set(name, value);
  }

  return new NextResponse(await response.text(), {
    status: response.status,
    headers,
  });
}

Le navigateur appelle seulement /api/interests/search. Ne lui permettez jamais de choisir l’hôte de destination et ne relayez pas son en-tête Authorization vers Orbit.

Ajoutez votre propre authentification utilisateur, validation et limitation anti-abus avant d’exposer cette route publiquement.