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 votre JWT de session, la même valeur que transporte votre cookie de session. Le plus simple pour l'obtenir est Se connecter avec Inklura dans l'Explorateur d'API (voir Authentification). Gardez-le hors du code source ; lisez-le depuis l'environnement :
export INKLURA_TOKEN="<session JWT>"
Le script agit en tant qu'utilisateur du token, avec ses permissions. Le token indique le locataire et le site d'origine de ce compte ; la portée de chaque appel est résolue à la requête et vérifiée au regard de ses accès (voir Sessions et tokens).
Vérifiez que le token est accepté avant tout travail réel en appelant auth.getSession
(montré ci-dessous). Un token invalide ou expiré n'est pas signalé comme tel : la requête est
traitée comme anonyme et l'appel échoue avec UNAUTHORIZED (401). auth.getSession demande
la permission auth:read : un compte qui ne l'a pas reçoit FORBIDDEN (403), même avec un
token valide.
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, et une erreur à
error.json.
const BASE = "https://manage.inklura.fr/api/trpc";
const auth = { Authorization: `Bearer ${process.env.INKLURA_TOKEN}` };
// Lit la réponse : renvoie la valeur, ou lève l'erreur tRPC.
async function unwrap(res: Response) {
const body = await res.json();
if (body.error) {
const { message, data } = body.error.json;
throw new Error(`${data?.code} (${data?.httpStatus}) : ${message}`);
}
return body.result.data.json;
}
// Query (GET) sans entrée : qui suis-je ?
const me = await unwrap(await fetch(`${BASE}/auth.getSession`, { headers: auth }));
console.log("session :", me.user.email);
// Query (GET) avec entrée : première page de produits
const input = encodeURIComponent(JSON.stringify({ json: { page: 0, limit: 10 } }));
const firstPage = await unwrap(
await fetch(`${BASE}/products.list?input=${input}`, { headers: auth }),
);
console.log("produits :", firstPage.total);
// Mutation (POST) : créer un client
const created = await unwrap(
await fetch(`${BASE}/clients.create`, {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({ json: { name: "Acme SARL", email: "contact@acme.example" } }),
}),
);
console.log("client créé :", created.id);
Une procédure qui ne prend aucune entrée, comme auth.getSession, s'appelle sans ?input= :
lui envoyer une entrée échoue à la validation.
En fetch brut, les valeurs que JSON ne sait pas représenter (dates notamment) arrivent sous
forme de chaînes dans json, leur type d'origine étant décrit à côté, dans meta. Le client
typé ci-dessous les reconvertit pour vous.
@trpc/client typé
Pour un appelant TypeScript, @trpc/client (v11) 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";
// AppRouter : le type du router de l'API si vous l'avez ; `any` fonctionne aussi, sans vérification de types.
const client = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: "https://manage.inklura.fr/api/trpc",
transformer: superjson,
headers() {
return { Authorization: `Bearer ${process.env.INKLURA_TOKEN}` };
},
}),
],
});
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, sans emballage
manuel {"json":…}. Voir Procédures tRPC pour les conventions d'appel et
les détails du batching.
clients.create exige name (non vide) ; email est facultatif mais doit être une adresse
valide s'il est fourni. Il faut aussi que votre compte ait le droit de modifier les clients :
sinon l'appel échoue avec FORBIDDEN.
Paginer une liste
products.list prend { page, limit }, avec page qui commence à 0 (limit vaut 10 par
défaut), et renvoie { items, total, page, limit, pages }. Elle accepte aussi des filtres
facultatifs : search (nom, description, référence ou SKU), active, categoryId, et le tri
sortBy / sortOrder (par défaut, les plus récents d'abord). Parcourez chaque page :
async function listAllProducts() {
const all = [];
const limit = 50;
for (let page = 0; ; page += 1) {
const res = await client.products.list.query({ page, limit });
all.push(...res.items);
if (page + 1 >= res.pages || res.items.length === 0) break;
}
return all;
}
La pagination est une convention plutôt qu'une garantie du framework : les noms de paramètres et le numéro de la première page varient d'une procédure à l'autre, confirmez donc 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
dans data (code, httpStatus, path), et les échecs de validation de l'entrée 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, path, zodError }
console.error(data?.code, data?.httpStatus); // BAD_REQUEST 400
if (data?.zodError) {
console.error("erreurs par champ :", data.zodError.fieldErrors);
}
} else {
throw err;
}
}
Avec fetch brut, lisez les mêmes champs dans error.json.data du corps parsé (comme le fait
unwrap plus haut). Voir Erreurs et limites de débit pour le mappage
code-vers-statut et la forme de zodError.
Connexe
- Procédures tRPC : conventions d'appel, batching, catalogue de routeurs
- Sessions et tokens : résolution de l'identité et portée locataire/site
- Erreurs et limites de débit : l'enveloppe d'erreur et les erreurs Zod
- Pagination et filtrage : les conventions de pagination