SDK TypeScript untuk API PDF: Lima Minit ke Panggilan Pertama, dan Apa yang Ditinggalkan kepada Anda
Gunakan @pdf123/sdk daripada TypeScript untuk menggabungkan fail, menambah tera air, membaca maklumat fail dan merantai beberapa alat dalam satu permintaan. SDK ini menangkap nama alat atau parameter yang salah eja sebelum apa-apa dimuat naik; penolakan pelayan membawa sebab dan petunjuk, manakala cubaan semula, pembatalan dan kegagalan separa dalam kelompok adalah urusan anda.

Apabila anda memanggil API PDF daripada Node, kit pembangunan perisian (SDK) @pdf123/sdk menangkap nama alat atau parameter yang salah eja sebelum sebarang fail dimuat naik. SDK ini tidak mencuba semula, tidak membatalkan bagi pihak anda dan tidak menyalurkan hasil secara strim. new Pdf123Client() secara lalai menuju ke https://pdf123.xyz tanpa nama; fail anda dimuat naik ke sana dan diproses di sana, kerana tiada enjin setempat.
Dua PDF dalam satu folder sudah cukup untuk digabungkan
Anda memerlukan Node 20.3 atau lebih baharu, atau Bun. Pakej ini ialah modul ES: letakkan kod dalam fail .mjs, atau jalankan npm pkg set type=module dahulu. Letakkan a.pdf dan b.pdf dalam direktori semasa.
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" }));
Selepas node merge.mjs, terminal mencetak laluan output yang anda berikan, merged.pdf, dan fail itu berada dalam direktori semasa. readFileInput dan saveResult terdapat dalam @pdf123/sdk/node. Entri akar hanya bergantung pada fetch dan menerima input sebagai { name, data } biasa, jadi persekitaran tanpa sistem fail boleh menggunakan klien yang sama. Hasilnya ialah { data, contentType, filename, json }; data ialah Uint8Array yang lengkap, dan Buffer.from(result.data) memberi anda Buffer.
Gabungkan PDF hanyalah satu daripada banyak alat.
Fail kembali dalam data, laporan dalam json
Setiap alat dipanggil dengan client.run(toolName, { input, params }). Kod di bawah menyambung merge.mjs daripada bahagian sebelumnya, dengan client dan saveResult sudah tersedia. Tempat anda membaca hasil bergantung pada medan returns daripada getTool, iaitu "file" atau "json": gunakan data untuk yang pertama dan json untuk yang kedua.
import { getTool } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";
// client datang daripada merge.mjs dalam bahagian sebelumnya
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"
Blok pertama menulis fail bertera air ke marked.pdf; dalam blok kedua, info.json ialah laporannya. Anda tidak perlu menghafal nama medan, nilai lalai atau nilai yang dibenarkan: getTool("watermark")?.fields ialah katalog itu, dan pdfx describe watermark pada baris perintah membaca katalog yang sama. TOOLS mengandungi kesemua 95 alat. Rujukan penuh ada dalam panduan SDK di halaman pembangun.
Untuk menggabungkan, kemudian menambah tera air, kemudian memampatkan, anda boleh menggunakan pipeline atau tiga panggilan run berturut-turut; pilihan bergantung pada sama ada anda mahu fail perantara. Sekali lagi ini menyambung daripada client di atas. pipeline melipat ketiga-tiga langkah menjadi satu permintaan, hasil perantara kekal di pelayan, dan pemanggil hanya menerima langkah terakhir, yang ditulis oleh kod di bawah ke out.pdf. Jika anda mahu fail daripada setiap langkah, panggil alat itu secara berasingan.
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" }));
Satu pipeline mempunyai paling banyak 8 langkah. Langkah ke-9 mendapat HTTP 400: at most 8 pipeline steps allowed.
Tanpa nama, dengan kunci, atau menuju ke pelayan anda sendiri
Jika anda menetapkan PDFX_API_BASE dan permintaan masih sampai ke https://pdf123.xyz, sebabnya new Pdf123Client() tidak membaca pemboleh ubah persekitaran; ia hanya melihat pilihan pembinanya.
Untuk panggilan tanpa nama, gunakan pembina itu seadanya. Dengan kunci, tulis new Pdf123Client({ apiKey: process.env.PDFX_API_KEY }); pengepala permintaannya ialah X-API-KEY.
Untuk menuju ke pelayan anda sendiri, gunakan clientFromEnv() daripada @pdf123/sdk/node. Ia membaca PDFX_API_BASE dan PDFX_API_KEY. Anda juga boleh menulis new Pdf123Client({ baseUrl: "http://localhost:8080" }) secara terus. Jika alamat tidak dapat dicapai, panggilan gagal; tiada mod luar talian. Apa yang anda dapat dan apa kosnya apabila fail kekal dalam rangkaian anda sendiri dibincangkan dalam Apa Sebenarnya yang Anda Dapat daripada Self-Host (dan Apa Kosnya).
Parameter yang salah ditangkap sebelum muat naik
Tanpa ini, fail dimuat naik dahulu dan nama medan yang salah eja hanya muncul sebagai 400 daripada pelayan. Jenis parameter bagi setiap alat dijana daripada katalog, jadi tiga kesilapan biasa gagal pada peringkat tsc:
| Apa yang anda tulis | Ralat pengkompil (petikan) |
|---|---|
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, ending with Did you mean to write 'watermarkText'? |
params: { angle: 45 } (rotate hanya menerima 90, 180, 270) |
Type '45' is not assignable to type β¦, followed by the allowed values |
Panggilan yang betul seperti { angle: 90 } atau { watermarkText: "DRAFT", fontSize: 30 } berjaya dikompil. Medan angka menerima nombor dan rentetan, jadi fontSize: 30 dan fontSize: "30" adalah setara. Projek yang tidak menggunakan TypeScript mendapat ralat yang sama semasa masa jalan, dan permintaan tidak pernah dihantar: kes ketiga memberi Field "angle" of "rotate" must be one of: 90, 180, 270, dan nama alat yang salah eja memberi unknown_tool, dengan nama yang serupa disenaraikan dalam mesej.
Apabila pelayan menolak, bercabang mengikut reason
Apabila pelayan menolak permintaan, SDK membaling Pdf123Error dengan status, code, reason dan problem.hint. Satu code boleh mempunyai beberapa nilai reason, jadi semak reason dahulu dan kembali kepada code. Tiga kegagalan biasa, dijalankan secara setempat dengan input yang sama, kelihatan seperti ini:
| Input | status | code | reason | hint (asalnya dalam bahasa Inggeris) |
|---|---|---|---|---|
| PDF disulitkan, tiada kata laluan diberi | 400 | bad_request |
password_required |
Provide the document password, or unlock the PDF first |
| Kata laluan salah | 400 | bad_request |
wrong_password |
Check the password and try again |
| Bukan PDF, atau fail rosak | 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" });
}
}
Apabila anda tahu kata laluannya, hantar password untuk satu fail; pembukaan kunci dan alat sasaran berlaku dalam permintaan yang sama. Untuk fail yang rosak, cuba Baiki PDF dahulu.
"Tiada hasil" perlu dibezakan. Apabila PDF ke CSV tidak menemui jadual dalam PDF, pelayan memulangkan 204 dan SDK membaling code: "no_content"; sebabnya ada dalam Eksport Jadual Kosong (204): PDF Anda Mungkin Tiada Lajur. Alat penapis bersyarat menganggap syarat yang palsu sebagai hasil biasa: ia tidak membaling ralat, dan memulangkan matched: false dengan data kosong.
Cubaan semula, memori dan pembatalan ialah tugas pemanggil
Ralat rangkaian dan respons 5xx dibaling seadanya; SDK tidak pernah mencuba semula dengan sendirinya. Untuk permintaan yang mengubah keadaan, hantar idempotencyKey anda sendiri: menghantar semula dengan kunci yang sama memulangkan hasil pertama dan bukan memproses sekali lagi, dan mekanisme serta had dihuraikan dalam Idempotency-Key: Cubaan Semula yang Selamat untuk Tugasan PDF. Hasil dibaca ke dalam memori secara penuh, tanpa strim. Apabila input dan output kedua-duanya besar, kira memori yang diduduki oleh kedua-duanya pada masa yang sama.
Pembatalan dan tamat masa ialah dua nilai code yang berbeza, dan satu panggilan hanya melaporkan yang berlaku dahulu. Contoh di bawah menguji keduanya dalam dua panggilan berasingan, supaya kedua-dua cabang benar-benar dapat dijalankan:
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") { /* anda yang membatalkannya */ }
}
try {
await client.run("compress", { input, timeoutMs: 60_000 });
} catch (error) {
if (error instanceof Pdf123Error && error.code === "timeout") { /* melebihi timeoutMs; kali ini tiada signal */ }
}
Sebaik sahaja isyarat henti (AbortSignal) tercetus, permintaan ditolak dengan code: "cancelled"; melebihi had masa memberi code: "timeout". Setiap permintaan mempunyai had masa lalai 5 minit, yang boleh anda ubah semasa mencipta klien atau atasi bagi setiap panggilan dengan timeoutMs. Dalam muat naik berketul, setiap permintaan membawa had masa itu secara berasingan. Pembatalan hanya menutup sambungan ini; tiada jaminan pelayan berhenti memproses.
Satu fail gagal, yang lain diteruskan, dan panggilan balik tiba mengikut urutan siap
Untuk kelompok input kepada alat satu fail, gunakan runBatch. Jika satu fail gagal, yang lain diteruskan. onResult dipanggil sebaik sahaja setiap fail siap, jadi ia berjalan mengikut urutan siap, dan index ialah kedudukan fail dalam tatasusunan input; tatasusunan yang dipulangkan sentiasa mengikut urutan input. Tulis bait ke cakera di dalam panggilan balik ini: retainData: false mengosongkan data sebaik sahaja panggilan balik selesai, jadi hasil yang tidak anda saveResult di sini akan hilang. Jika larian terganggu, fail yang sudah ditulis kekal.
Andaikan folder itu mempunyai tiga PDF yang baik, a.pdf, b.pdf dan locked.pdf yang disulitkan (kata laluan secret), serta fail rosak broken.pdf yang hanya mengandungi beberapa aksara yang ditaip:
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,
});
Secara lalai dua fail diproses pada satu masa; ubahnya dengan concurrency. fileSource(path) membaca fail daripada cakera hanya apabila tiba gilirannya, jadi kelompok besar fail besar tidak pernah berada dalam memori sekali gus. passwordFor membolehkan kelompok yang mencampurkan fail berkunci dan tidak berkunci berjalan sekali gus. Apabila empat fail di atas dijalankan secara setempat, panggilan balik menerima:
1 broken.pdf invalid_pdf
0 a.pdf ok
2 b.pdf ok
3 locked.pdf ok
Urutan siap boleh berbeza pada setiap larian; ini hanyalah rupa satu larian. retainData: false menjadikan data dalam tatasusunan yang dipulangkan kosong; fail yang berjaya sudah ditulis ke out/ oleh saveResult di atas. Apabila anda menghantar idempotencyKey kepada runBatch, kunci yang sebenarnya dihantar bagi setiap fail ialah <key>:<index>.
Muat naik berketul bermula hanya apabila jumlahnya melebihi 95 MiB
Badan permintaan terus dihadkan kepada 100 MiB, dan apa-apa yang lebih besar ditolak; lihat Apabila muat naik PDF besar ditolak: had 100 MiB pada badan permintaan dan ralat yang menunjuk ke arah salah untuk butirannya. Apabila semua fail dalam satu permintaan berjumlah lebih daripada 95 MiB, SDK beralih kepada muat naik berketul, dan panggilan client.run anda tidak berubah. Maksimum lalai pelayan bagi satu muat naik ialah 500 MiB; apabila anda self-host, laraskannya dengan PDFX_UPLOAD_MAX_BYTES.
Untuk operasi yang sama ditulis dalam curl, MCP dan baris perintah, lihat Operasi Sama, Empat Klien: Pelayar, curl, MCP, pdfx: catatan itu meletakkan keempat-empat panggilan bersebelahan, dan catatan ini hanya mengembangkan SDK. Halaman pakej ini di npm ialah @pdf123/sdk.