Aller au contenu

Client TypeScript (@dustid/apid-client)

@dustid/apid-client est le client TypeScript typé pour l’API DUST. Il s’agit du même client que celui utilisé en production par l’application web DICE, et ses types de requêtes et de réponses sont générés directement à partir de la spécification OpenAPI de l’API, ce qui lui permet de rester parfaitement synchronisé avec le serveur.

Le paquet n’est pas publié dans le registre npm public. Il est distribué par DUST et mis à la disposition des clients d’intégration sur demande (contactez support@dustidentity.com). npm install @dustid/apid-client ne le trouvera pas.

Si vous préférez ne pas ajouter cette dépendance, vous pouvez obtenir la même sûreté de typage en générant des types à partir de la spécification OpenAPI — c’est exactement ainsi que les propres types de ce client sont produits — et appeler l’API avec un simple fetch. Le guide de démarrage rapide procède de cette manière afin de fonctionner sans aucune installation.

Vérifiez les points suivants avant de prévoir l’utilisation du client :

ExigenceDétail
Environnement d’exécutionUn fetch global : Node.js 18+, Bun ou Deno. Vous pouvez injecter votre propre implémentation à l’aide de l’option fetcher (proxys, nouvelles tentatives, doublures de test).
Chaîne d’outils TypeScriptLes points d’entrée du paquet correspondent à du code source TypeScript, et non à du JavaScript compilé. Votre bundler ou votre environnement d’exécution doit le transpiler — un simple node dist/app.js utilisant du code source non transpilé ne fonctionnera pas.
Dépendances d’exécutionLe client comporte des dépendances : il déclare arktype (utilisé pour valider les charges utiles d’erreur), ainsi que des paquets utilitaires internes à DUST, fournis avec la distribution. Tenez-en compte pour toute intégration du code en interne, vérification des licences ou installation dans un environnement isolé.
Lieu d’exécutionCôté serveur uniquement — consultez l’avertissement à la fin de cette page.
import { ApidClient } from "@dustid/apid-client";
const client = new ApidClient({
baseUrl: "https://apid.dustid.io",
bearerToken: token, // Authorization: Bearer <token>
organizationId: orgId, // sent as Dust-Ctx-Org-Id
teamId: teamId, // sent as Dust-Ctx-Team-Id
});

Voici le type complet des options :

type ApidClientOptions = {
baseUrl: string;
bearerToken?: string;
organizationId?: string; // Dust-Ctx-Org-Id header
teamId?: string; // Dust-Ctx-Team-Id header
fetcher?: typeof globalThis.fetch; // custom fetch (proxies, testing)
defaultHeaders?: HeadersInit | (() => HeadersInit); // e.g. Dust-Ctx-Locale
logger?: Logger; // debug/error request logging
};

organizationId et teamId correspondent aux en-têtes de contexte ; lorsque teamId est omis, le serveur utilise par défaut l’équipe racine de l’organisation. Utilisez defaultHeaders pour tout élément supplémentaire que vous souhaitez inclure dans chaque requête — par exemple, des messages d’erreur localisés :

const client = new ApidClient({
baseUrl,
bearerToken,
organizationId,
defaultHeaders: { "Dust-Ctx-Locale": "zh-CN" },
});

Les clients sont immuables ; deux fonctions auxiliaires renvoient une copie reconfigurée, ce qui permet de définir facilement un périmètre par requête ou par utilisateur :

const asOtherTeam = client.withContext({ teamId: otherTeamId });
const asFreshToken = client.withToken(newBearerToken);

Le client regroupe les points de terminaison par ressources : client.me, client.threads, client.bundles, client.files, client.tags (opérations sur les identifiants — les points de terminaison /api/v1/tags/*), client.teams, client.sharing, client.templates, client.events, client.relations, client.threadLinks, client.assemblies, client.transfers, client.slices, client.imports, client.fabric, client.users, client.certificates et client.certificateForms.

Les noms de méthodes correspondent à ceux de la référence. Voici deux exemples réels avec des fiches :

// GET /api/v1/threads — cursor-paginated list
const page = await client.threads.list({ pageSize: 50, q: "tire" });
for (const thread of page.threads) {
console.log(thread.threadId, thread.name);
}
if (page.next) {
const nextPage = await client.threads.list({ pageSize: 50, cursor: page.next });
}
// POST /api/v1/threads — create, unwrapped to the single created record
const created = await client.threads.createOne({
type: "single",
thread: { name: "Tire SZ3J-11-ZJ17" },
data: [{ name: "Serial Number", type: "text", value: { text: "SZ3J-11-ZJ17" } }],
});
// GET /api/v1/threads/{thread_id}
const record = await client.threads.get(created.threadId);
console.log(record.thread.name, record.events.length);

threads.create renvoie la réponse brute du traitement par lots ({ created, uploadResponses }) ; threads.createOne est une méthode pratique qui renvoie created[0] et lève une exception si le serveur n’a rien créé.

Tous les types de requêtes et de réponses sont exportés depuis la racine du paquet (ThreadCreateRequest, ThreadQueryResponse, ThreadGetResponse, …), de même que les types bruts générés paths / components / operations issus de la spécification.

Les méthodes renvoient la réponse JSON analysée en cas de réussite et lèvent une ApiError pour tout statut autre que 2xx. ApiError contient le corps d’erreur standard de l’API :

import { ApiError } from "@dustid/apid-client";
try {
await client.threads.get(threadId);
} catch (error) {
if (error instanceof ApiError) {
// error.code stable error code, e.g. "NOT_FOUND", "UNAUTHORIZED"
// error.status HTTP status number
// error.message localized human-readable message
// error.detail optional extra context (validation issues, etc.)
// error.body the full { code, message, status, detail } payload
if (error.code === "UNAUTHORIZED") {
// token expired — re-exchange the API key and retry
}
} else {
throw error; // network failure or non-JSON response
}
}

Deux comportements particuliers sont à connaître : les réponses 204/205 sont résolues en undefined, et une réponse qui ne contient pas de JSON valide lève une simple Error (et non une ApiError). Si vous fournissez un logger, chaque requête ayant échoué est journalisée avec son x-request-id afin que l’assistance puisse établir la corrélation.

Solution alternative : générer vos propres types

Section intitulée « Solution alternative : générer vos propres types »

L’API fournit sa spécification OpenAPI 3 à l’adresse https://apid.dustid.io/api/openapi.json. openapi-typescript la transforme en une définition paths/components entièrement typée que vous pouvez utiliser avec un simple fetch ou avec tout adaptateur de récupération piloté par une spécification :

Fenêtre de terminal
npx openapi-typescript@7 https://apid.dustid.io/api/openapi.json -o <generated-types-file>
import type { paths } from "./dust-api";
type ThreadList =
paths["/api/v1/threads"]["get"]["responses"]["200"]["content"]["application/json"];

N’oubliez pas de définir vous-même les en-têtes Authorization, Dust-Ctx-Org-Id et Dust-Ctx-Team-Id — consultez les conventions relatives aux requêtes. Régénérez les types chaque fois que vous adoptez de nouvelles fonctionnalités de l’API ; la spécification située à l’adresse /api/openapi.json est toujours à jour pour le serveur depuis lequel vous l’avez récupérée.