Salta ai contenuti

Client TypeScript (@dustid/apid-client)

@dustid/apid-client è il client TypeScript tipizzato per l’API DUST. È lo stesso client utilizzato in produzione dall’applicazione web DICE e i relativi tipi di richiesta/risposta vengono generati direttamente dalla specifica OpenAPI dell’API, quindi rimane perfettamente sincronizzato con il server.

Il pacchetto non è pubblicato nel registro npm pubblico. Viene distribuito da DUST ed è disponibile su richiesta per i clienti che effettuano integrazioni (contatta support@dustidentity.com). npm install @dustid/apid-client non riuscirà a trovarlo.

Se preferisci non aggiungere questa dipendenza, puoi ottenere la stessa sicurezza dei tipi generando i tipi dalla specifica OpenAPI — è esattamente così che vengono prodotti i tipi di questo client — e chiamare l’API con il semplice fetch. La guida introduttiva segue questo approccio, così può essere eseguita senza installare nulla.

Verifica quanto segue prima di pianificare l’utilizzo del client:

RequisitoDettaglio
RuntimeUn fetch globale: Node.js 18+, Bun o Deno. Puoi fornire una tua implementazione tramite l’opzione fetcher (proxy, nuovi tentativi, oggetti simulati per i test).
Toolchain TypeScriptGli entry point del pacchetto vengono risolti in codice sorgente TypeScript, non in JavaScript compilato. Il bundler o il runtime deve eseguirne la transpilazione: il semplice node dist/app.js con codice sorgente non transpilato non funzionerà.
Dipendenze di runtimeIl client non è privo di dipendenze: dichiara arktype (utilizzato per convalidare i payload degli errori) oltre a pacchetti helper interni di DUST, inclusi nella distribuzione. Tienine conto per qualsiasi operazione di inclusione diretta delle dipendenze, verifica delle licenze o installazione in un ambiente isolato.
Luogo di esecuzioneSolo lato server — consulta l’avvertenza alla fine di questa pagina.
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
});

Il tipo completo delle opzioni:

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 e teamId corrispondono alle intestazioni di contesto; quando teamId viene omesso, il server utilizza per impostazione predefinita il team radice dell’organizzazione. Usa defaultHeaders per qualsiasi elemento aggiuntivo da includere in ogni richiesta, ad esempio messaggi di errore localizzati:

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

I client sono immutabili; due metodi helper restituiscono una copia riconfigurata, rendendo poco costosa la definizione dell’ambito per richiesta o per utente:

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

Il client raggruppa gli endpoint in risorse: client.me, client.threads, client.bundles, client.files, client.tags (operazioni sugli Identificatori — gli endpoint /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 e client.certificateForms.

I nomi dei metodi rispecchiano la documentazione di riferimento. Ecco due esempi reali con le schede:

// 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 restituisce la risposta batch non elaborata ({ created, uploadResponses }); threads.createOne è un metodo di utilità che restituisce created[0] e genera un’eccezione se il server non ha creato alcun elemento.

Tutti i tipi di richiesta e risposta vengono esportati dalla radice del pacchetto (ThreadCreateRequest, ThreadQueryResponse, ThreadGetResponse, …), insieme ai tipi paths / components / operations non elaborati generati dalla specifica.

In caso di esito positivo, i metodi restituiscono la risposta JSON analizzata e, per qualsiasi stato diverso da 2xx, generano un’eccezione ApiError. ApiError contiene il corpo dell’errore standard dell’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
}
}

È utile conoscere due comportamenti nei casi limite: le risposte 204/205 vengono risolte in undefined, mentre una risposta che non contiene JSON valido genera un semplice Error (non un ApiError). Se specifichi un logger, ogni richiesta non riuscita viene registrata insieme al relativo x-request-id, per consentire al supporto di correlarla.

L’API espone la propria specifica OpenAPI 3 all’indirizzo https://apid.dustid.io/api/openapi.json. openapi-typescript la converte in una definizione paths/components completamente tipizzata, utilizzabile con il semplice fetch o con qualsiasi wrapper per fetch basato sulla specifica:

Terminal window
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"];

Ricorda di impostare autonomamente le intestazioni Authorization, Dust-Ctx-Org-Id e Dust-Ctx-Team-Id; consulta le Convenzioni per le richieste. Rigenera i tipi ogni volta che adotti nuove funzionalità dell’API; la specifica disponibile in /api/openapi.json è sempre aggiornata per il server dal quale viene recuperata.