Appeler l'API depuis un script

Ce guide appelle l'API de plateforme tRPC depuis un script Node ou Bun autonome. Il couvre l'obtention d'un token, une version en fetch brut (pour voir le format de transport superjson), la version typée @trpc/client, la pagination d'une liste et la gestion de l'enveloppe d'erreur.

Obtenir un token

Les appelants programmatiques s'authentifient avec un JWT de session dans l'en-tête Authorization :

Authorization: Bearer <session JWT>

Le token est le JWT de session HS256 (signé avec AUTH_SECRET) — la même valeur que transporte le cookie __Secure-authjs.session-token. Gardez-le hors du code source ; lisez-le depuis l'environnement :

export INKLURA_TOKEN="<session JWT>"

Vérifiez qu'il se résout avant tout travail réel en appelant auth.getSession (montré ci-dessous).

fetch brut

Utile pour voir le format de transport. Les requêtes sont en GET avec l'entrée URL-encodée dans ?input={"json":<value>} ; les mutations sont en POST avec le corps {"json":<value>}. Le résultat est imbriqué à result.data.json.

const BASE = "https://manage.inklura.fr/api/trpc";
const auth = { Authorization: `Bearer ${process.env.INKLURA_TOKEN}` };

// Query (GET): qui suis-je ?
const input = encodeURIComponent(JSON.stringify({ json: {} }));
const meRes = await fetch(`${BASE}/auth.getSession?input=${input}`, {
  headers: auth,
});
const me = (await meRes.json()).result.data.json;
console.log("session:", me);

// Mutation (POST): créer un client
const createRes = await fetch(`${BASE}/clients.create`, {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({ json: { name: "Acme SARL", email: "contact@acme.example" } }),
});
const created = (await createRes.json()).result.data.json;
console.log("created:", created.id);

Pour une procédure qui ne prend aucune entrée, vous pouvez omettre ?input= entièrement.

@trpc/client typé

Pour un appelant TypeScript, @trpc/client gère l'emballage superjson et le batching pour vous. Configurez le transformateur superjson sur un httpBatchLink et définissez-y l'en-tête Authorization :

import { createTRPCClient, httpBatchLink } from "@trpc/client";
import superjson from "superjson";

const client = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: "https://manage.inklura.fr/api/trpc",
      transformer: superjson,
      headers() {
        return {
          Authorization: `Bearer ${process.env.INKLURA_TOKEN}`,
          // Optionnel : cibler la portée tenant / site :
          "X-Tenant-Id": process.env.INKLURA_TENANT_ID ?? "",
          "X-Site-Id": process.env.INKLURA_SITE_ID ?? "",
        };
      },
    }),
  ],
});

const session = await client.auth.getSession.query();
const created = await client.clients.create.mutate({
  name: "Acme SARL",
  email: "contact@acme.example",
});

Avec le transformateur configuré, vous passez et recevez des valeurs simples — aucun emballage manuel {"json":…}. Voir Procédures tRPC pour les conventions d'appel et les détails du batching.

Paginer une liste

Les procédures de liste suivent la convention { page, pageSize } et renvoient { items, total, page, pageSize }. Parcourez chaque page :

async function listAllProducts() {
  const all = [];
  let page = 1;
  const pageSize = 50;
  for (;;) {
    const res = await client.products.list.query({ page, pageSize });
    all.push(...res.items);
    if (all.length >= res.total || res.items.length === 0) break;
    page += 1;
  }
  return all;
}

La pagination est une convention plutôt qu'une garantie du framework — confirmez la forme pour la procédure que vous appelez. Voir Pagination et filtrage.

Gérer les erreurs

Les échecs reviennent sous forme d'enveloppe d'erreur tRPC standard ; les champs utiles sont sous error.data (code, httpStatus), et les échecs de validation Zod ajoutent data.zodError. Le client typé lève une TRPCClientError dont le data les transporte :

import { TRPCClientError } from "@trpc/client";

try {
  await client.clients.create.mutate({ name: "", email: "not-an-email" });
} catch (err) {
  if (err instanceof TRPCClientError) {
    const data = err.data; // { code, httpStatus, ... }
    console.error(data?.code, data?.httpStatus);
    if (data?.zodError) {
      console.error("field errors:", data.zodError.fieldErrors);
    }
  } else {
    throw err;
  }
}

Avec fetch brut, lisez les mêmes champs dans le error.data du corps parsé. Voir Erreurs et limites de débit pour le mappage code-vers-statut et la forme de zodError.

Connexe