SDK de TypeScript per a l'API de PDF: cinc minuts fins a la primera crida i què us deixa a vosaltres
Useu @pdf123/sdk des de TypeScript per unir fitxers, afegir marques d'aigua, llegir la informació d'un fitxer i encadenar diverses eines en una sola petició. Detecta un nom d'eina o un paràmetre mal escrit abans de pujar res; els rebuigs del servidor porten un motiu i una pista, mentre que els reintents, la cancel·lació i els errors parcials d'un lot els heu de gestionar vosaltres.

Quan crideu l'API de PDF des de Node, el kit de desenvolupament @pdf123/sdk (SDK) detecta un nom d'eina o un paràmetre mal escrit abans de pujar cap fitxer. No reintenta, no cancel·la per vosaltres i no retorna els resultats en flux. new Pdf123Client() apunta per defecte de manera anònima a https://pdf123.xyz; els fitxers s'hi pugen i s'hi processen, ja que no hi ha motor local.
Amb dos PDF en una carpeta ja podeu unir-los
Cal Node 20.3 o posterior, o Bun. El paquet és un mòdul ES: poseu el codi en un fitxer .mjs, o executeu primer npm pkg set type=module. Poseu a.pdf i b.pdf al directori actual.
npm install @pdf123/sdk
// merge.mjs
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";
const client = new Pdf123Client();
const merged = await client.run("merge", {
input: [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
});
console.log(await saveResult(merged, { output: "merged.pdf" }));
Després de node merge.mjs el terminal imprimeix la ruta de sortida que heu passat, merged.pdf, i el fitxer és al directori actual. readFileInput i saveResult són a @pdf123/sdk/node. L'entrada arrel només depèn de fetch i accepta les entrades com a simples { name, data }, de manera que un entorn sense sistema de fitxers pot usar el mateix client. Un resultat és { data, contentType, filename, json }; data és un Uint8Array sencer, i Buffer.from(result.data) us dona un Buffer.
Uneix PDF és només una de les eines.
Els fitxers tornen a data i els informes a json
Cada eina es crida com client.run(toolName, { input, params }). El codi següent continua merge.mjs de la secció anterior, amb client i saveResult ja disponibles. Des d'on s'ha de llegir el resultat depèn del camp returns que retorna getTool, que és "file" o "json": useu data per al primer i json per al segon.
import { getTool } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";
// client comes from merge.mjs in the previous section
const marked = await client.run("watermark", {
input: await readFileInput("a.pdf"),
params: { watermarkText: "DRAFT", fontSize: 40 },
});
console.log(await saveResult(marked, { output: "marked.pdf" }));
const info = await client.run("get-info", { input: await readFileInput("a.pdf") });
console.log(info.json.FileSize, info.json.Encrypted);
console.log(getTool("get-info")?.returns); // "json"
El primer bloc escriu el fitxer amb marca d'aigua a marked.pdf; al segon, info.json és l'informe. No cal memoritzar noms de camps, valors per defecte ni valors permesos: getTool("watermark")?.fields és aquest catàleg, i pdfx describe watermark a la línia d'ordres llegeix el mateix. TOOLS conté les 95 eines. La referència completa és a la guia de l'SDK a la pàgina per a desenvolupadors.
Per unir, després afegir una marca d'aigua i després comprimir, podeu usar pipeline o tres crides run seguides; quina depèn de si voleu els fitxers intermedis. Tornem a continuar des del client d'abans. pipeline plega els tres passos en una sola petició, els resultats intermedis es queden al servidor i qui crida només rep l'últim pas, que el codi següent escriu a out.pdf. Si voleu el fitxer de cada pas, crideu-los per separat.
const result = await client.pipeline(
[{ tool: "merge" }, { tool: "watermark", params: { watermarkText: "DRAFT" } }, { tool: "compress" }],
[await readFileInput("a.pdf"), await readFileInput("b.pdf")],
);
console.log(await saveResult(result, { output: "out.pdf" }));
Un pipeline té com a màxim 8 passos. Un novè pas rep HTTP 400: at most 8 pipeline steps allowed.
Anònim, amb clau o apuntant al vostre servidor
Si heu definit PDFX_API_BASE i les crides continuen anant a https://pdf123.xyz, és perquè new Pdf123Client() no llegeix variables d'entorn; només mira les opcions del constructor.
Per a crides anònimes, useu el constructor tal qual. Amb clau, escriviu new Pdf123Client({ apiKey: process.env.PDFX_API_KEY }); la capçalera de la petició és X-API-KEY.
Per apuntar al vostre servidor, useu clientFromEnv() de @pdf123/sdk/node. Llegeix PDFX_API_BASE i PDFX_API_KEY. També podeu escriure directament new Pdf123Client({ baseUrl: "http://localhost:8080" }). Si l'adreça no és accessible, la crida falla; no hi ha mode fora de línia. Què us aporta i quant costa tenir els fitxers dins la vostra xarxa ho trobareu a Què us aporta realment l'autoallotjament (i quant costa).
Un paràmetre incorrecte es detecta abans de la pujada
Sense això, el fitxer es pujaria primer i un nom de camp mal escrit només apareixeria com un 400 del servidor. Els tipus dels paràmetres de cada eina es generen a partir del catàleg, de manera que tres errors habituals fallen ja a l'etapa de tsc:
| El que escriviu | Error del compilador (fragment) |
|---|---|
client.run("rotat", { input }) |
Argument of type '"rotat"' is not assignable to parameter of type 'ToolId' |
params: { watermarkTxt: "DRAFT" } |
Object literal may only specify known properties, but 'watermarkTxt' does not exist, que acaba amb Did you mean to write 'watermarkText'? |
params: { angle: 45 } (girar només accepta 90, 180, 270) |
Type '45' is not assignable to type …, seguit dels valors permesos |
Les crides correctes, com { angle: 90 } o { watermarkText: "DRAFT", fontSize: 30 }, es compilen. Els camps numèrics accepten tant nombres com cadenes, de manera que fontSize: 30 i fontSize: "30" són equivalents. Un projecte que no usa TypeScript obté els mateixos errors en temps d'execució, i la petició no s'envia mai: el tercer cas dona Field "angle" of "rotate" must be one of: 90, 180, 270, i un nom d'eina mal escrit dona unknown_tool, amb els noms semblants llistats al missatge.
Quan el servidor rebutja, bifurqueu per reason
Quan el servidor rebutja una petició, l'SDK llança Pdf123Error amb status, code, reason i problem.hint. Un mateix code pot tenir diversos valors de reason, així que mireu primer reason i recorreu a code si no hi és. Tres errors habituals, executats en local amb la mateixa entrada, tenen aquest aspecte:
| Entrada | status | code | reason | hint (l'original és en anglès) |
|---|---|---|---|---|
| PDF xifrat, sense contrasenya | 400 | bad_request |
password_required |
Provide the document password, or unlock the PDF first |
| Contrasenya incorrecta | 400 | bad_request |
wrong_password |
Check the password and try again |
| No és un PDF, o és un fitxer malmès | 400 | invalid_document |
invalid_pdf |
Upload a valid, undamaged PDF; you can try repairing it first |
import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";
const client = new Pdf123Client();
const input = await readFileInput("locked.pdf");
try {
await client.run("compress", { input });
} catch (error) {
if (!(error instanceof Pdf123Error)) throw error;
console.error(error.status, error.code, error.reason, error.problem?.hint);
if (error.reason === "password_required") {
await client.run("compress", { input, password: "secret" });
}
}
Quan sabeu la contrasenya, passeu password per a un sol fitxer; el desbloqueig i l'eina de destinació es fan en la mateixa petició. Per a un fitxer malmès, proveu primer Repara PDF.
Cal distingir els casos de «cap resultat». Quan PDF a CSV no troba cap taula al PDF, el servidor retorna 204 i l'SDK llança code: "no_content"; el motiu és a Exportació de taula buida (204): el teu PDF probablement no té columnes. Les eines de filtre condicional tracten una condició falsa com un resultat normal: no llancen cap error i retornen matched: false amb data buit.
Els reintents, la memòria i la cancel·lació van a càrrec vostre
Els errors de xarxa i les respostes 5xx es llancen tal com són; l'SDK mai no reintenta pel seu compte. Per a una petició que canvia l'estat, passeu el vostre propi idempotencyKey: tornar a enviar amb la mateixa clau retorna el primer resultat en lloc de processar de nou, i el mecanisme i els límits són a Idempotency-Key: reintents segurs per a tasques PDF. Els resultats es llegeixen a la memòria sencers, sense flux. Quan l'entrada i la sortida són grans, compteu la memòria que ocupen alhora.
La cancel·lació i el temps d'espera són dos valors diferents de code. Una sola crida només informa del que passi primer. L'exemple següent els prova en dues crides separades, perquè les dues branques es puguin executar de debò:
import { Pdf123Client, Pdf123Error } from "@pdf123/sdk";
import { readFileInput } from "@pdf123/sdk/node";
const client = new Pdf123Client();
const input = await readFileInput("a.pdf");
const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);
try {
await client.run("compress", { input, signal: controller.signal });
} catch (error) {
if (error instanceof Pdf123Error && error.code === "cancelled") { /* l'heu cancel·lat vosaltres */ }
}
try {
await client.run("compress", { input, timeoutMs: 60_000 });
} catch (error) {
if (error instanceof Pdf123Error && error.code === "timeout") { /* ha superat timeoutMs; sense signal aquesta vegada */ }
}
Tan bon punt salta el senyal d'avortament (AbortSignal), la petició es rebutja amb code: "cancelled"; superar el temps d'espera dona code: "timeout". Cada petició té un temps d'espera per defecte de 5 minuts, que podeu canviar en crear el client o substituir per crida amb timeoutMs. En una pujada per parts, cada petició porta aquest temps d'espera pel seu compte. Cancel·lar només tanca aquesta connexió; no hi ha garantia que el servidor aturi el processament.
Un fitxer falla, la resta continuen, i les crides de retorn arriben per ordre d'acabament
Per a un lot d'entrades d'una eina d'un sol fitxer, useu runBatch. Si un fitxer falla, els altres continuen. onResult es crida en el moment en què acaba cada fitxer, de manera que s'executa per ordre d'acabament, i index és la posició del fitxer a la matriu d'entrada; la matriu retornada sempre és en l'ordre d'entrada. Escriviu els bytes al disc dins d'aquesta crida de retorn: retainData: false buida data quan la crida de retorn acaba, de manera que un resultat que no deseu aquí amb saveResult es perd. Si l'execució s'interromp, els fitxers ja escrits es mantenen.
Suposem que la carpeta té tres PDF bons, a.pdf, b.pdf i un locked.pdf xifrat (contrasenya secret), més un fitxer malmès broken.pdf que només conté uns quants caràcters escrits:
import { Pdf123Client } from "@pdf123/sdk";
import { fileSource, saveResult } from "@pdf123/sdk/node";
const client = new Pdf123Client();
const results = await client.runBatch("compress", [
fileSource("a.pdf"), fileSource("broken.pdf"), fileSource("b.pdf"), fileSource("locked.pdf"),
], {
concurrency: 2,
passwordFor: (file) => (file.name === "locked.pdf" ? "secret" : undefined),
onResult: async (entry, index) => {
console.log(index, entry.input.name, entry.ok ? "ok" : entry.error.reason);
if (entry.ok) await saveResult(entry.result, { output: "out/" });
},
retainData: false,
});
Per defecte es processen dos fitxers alhora; es canvia amb concurrency. fileSource(path) només llegeix un fitxer del disc quan li toca el torn, de manera que un lot gran de fitxers grans mai no és tot alhora a la memòria. passwordFor permet que un lot que barreja fitxers bloquejats i desbloquejats s'executi d'una tirada. En executar els quatre fitxers anteriors en local, la crida de retorn va rebre:
1 broken.pdf invalid_pdf
0 a.pdf ok
2 b.pdf ok
3 locked.pdf ok
L'ordre d'acabament pot ser diferent a cada execució; això és només com es va veure una execució. retainData: false fa que data quedi buit a la matriu retornada; els fitxers reeixits ja s'havien escrit a out/ amb el saveResult d'abans. Quan passeu idempotencyKey a runBatch, la clau que s'envia realment per a cada fitxer és <key>:<index>.
La pujada per parts només comença per sobre de 95 MiB en total
El cos d'una petició directa té un límit de 100 MiB, i tot el que el superi es rebutja; per als detalls vegeu Quan es rebutja la càrrega d'un PDF gran: el límit de 100 MiB del cos de la petició i l'error que us porta pel camí equivocat. Quan tots els fitxers d'una petició sumen més de 95 MiB, l'SDK passa a la pujada per parts, i la vostra crida a client.run no canvia. El màxim per defecte del servidor per a una pujada és de 500 MiB; si allotgeu pel vostre compte, ajusteu-lo amb PDFX_UPLOAD_MAX_BYTES.
Per veure la mateixa operació escrita amb curl, MCP i la línia d'ordres, consulteu La mateixa operació, quatre clients: navegador, curl, MCP i pdfx: aquell article posa les quatre crides una al costat de l'altra, i aquest només desplega l'SDK. La pàgina del paquet a npm és @pdf123/sdk.