· Nacho Coll · Tutorials  · 9 minit bacaan

IPFS Upload API — Tutorial pembangun yang lengkap

Belajar muat naik fail ke IPFS melalui REST API. Contoh kod penuh dalam JavaScript, Node.js dan curl. Muat naik JSON, imej, gunakan token bertandatangan untuk muat naik sebelah klien.

Belajar muat naik fail ke IPFS melalui REST API. Contoh kod penuh dalam JavaScript, Node.js dan curl. Muat naik JSON, imej, gunakan token bertandatangan untuk muat naik sebelah klien.

IPFS Upload API — Tutorial pembangun yang lengkap

Memuat naik fail ke IPFS sepatutnya semudah membuat permintaan POST. Dalam tutorial ini anda akan melakukan tepat itu — muat naik dokumen JSON, imej, dan PDF ke IPFS dengan tidak lebih daripada fetch() dan kunci API. Pada akhirnya anda akan mempunyai skrip Node.js yang lengkap yang memuat naik kandungan, menyenaraikan fail, mendapatkan metadata, dan menjana token bertandatangan untuk muat naik sebelah klien yang selamat. Baru kepada IPFS? Mulakan dengan Apa itu IPFS Pinning? untuk memahami asasnya sebelum menyelam ke dalam kod.

IPFS Ninja API keys management page

Apa yang akan anda bina

  • Muat naik objek JSON ke IPFS dan dapatkan kembali pengenal kandungan (CID).
  • Muat naik imej binari dari cakera.
  • Lampirkan penerangan dan metadata tersuai pada muat naik.
  • Tanyakan sejarah muat naik anda mengikut julat tarikh.
  • Dapatkan butiran untuk fail tertentu.
  • Cipta token bertandatangan dengan masa terhad supaya pelayar boleh memuat naik secara langsung tanpa mendedahkan kunci API anda.
  • Kendalikan ralat dan laksanakan logik cuba semula.

Semuanya berjalan terhadap satu URL asas: https://api.ipfs.ninja

1. Persediaan — Daftar dan dapatkan kunci API

  1. Daftar untuk akaun percuma (kad kredit tidak diperlukan).
  2. Pergi ke API Keys di bar sisi dashboard.
  3. Klik Create key, beri ia nama, dan salin kunci dengan segera — ia tidak akan ditunjukkan lagi.
API Keys page — create and manage your keys

Kunci anda kelihatan seperti bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6. Setiap contoh di bawah menghantarnya dalam header X-Api-Key.

2. Muat naik JSON ke IPFS

Muat naik paling mudah: hantar objek JavaScript biasa sebagai content dan API akan menyirikannya, mengepinnya ke IPFS, dan memulangkan CID.

// upload-json.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const payload = {
  content: {
    name: "Galactic Badge #42",
    description: "Proof of attendance — Galactic Meetup 2026",
    attributes: [
      { trait_type: "Event", value: "Galactic Meetup" },
      { trait_type: "Year", value: 2026 }
    ]
  }
};

const res = await fetch(`${API}/upload/new`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY
  },
  body: JSON.stringify(payload)
});

const data = await res.json();
console.log("CID :", data.cid);
console.log("Size:", data.sizeMB, "MB");
console.log("IPFS:", data.uris.ipfs);
console.log("URL :", data.uris.url);

Jalankan dengan node upload-json.mjs. Respons yang berjaya kelihatan seperti ini:

{
  "cid": "bafkreigx7gq...",
  "sizeMB": 0.0004,
  "uris": {
    "ipfs": "ipfs://bafkreigx7gq...",
    "url": "https://ipfs.ninja/ipfs/bafkreigx7gq..."
  }
}

Medan url menunjuk ke gateway HTTP awam, jadi kandungan boleh diakses dengan segera dalam mana-mana pelayar.

3. Muat naik imej

Fail binari (imej, PDF, audio) dihantar sebagai rentetan berkod base64 dalam medan content.

// upload-image.mjs
import { readFileSync } from "node:fs";

const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const imageBuffer = readFileSync("./photo.png");
const base64 = imageBuffer.toString("base64");

const res = await fetch(`${API}/upload/new`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY
  },
  body: JSON.stringify({ content: base64 })
});

const data = await res.json();
console.log("Image CID:", data.cid);
console.log("Gateway  :", data.uris.url);

API mengesan jenis MIME secara automatik — PNG, JPEG, WebP, GIF, dan PDF semua disokong. Tiada header tambahan atau override content-type diperlukan.

Dengan curl, operasi yang sama kelihatan seperti ini:

BASE64=$(base64 -w 0 photo.png)

curl -X POST https://api.ipfs.ninja/upload/new \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: bws_your_key_here" \
  -d "{\"content\": \"$BASE64\"}"

4. Muat naik dengan metadata

Setiap muat naik menerima dua medan pilihan: description (label teks bebas) dan metadata (pasangan kunci-nilai sewenang-wenangnya). Kedua-duanya disimpan bersebelahan dengan CID dan dipulangkan apabila anda menyenaraikan atau mendapatkan fail kemudian.

// upload-with-metadata.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const res = await fetch(`${API}/upload/new`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY
  },
  body: JSON.stringify({
    content: { title: "Meeting Notes", body: "Q1 roadmap recap..." },
    description: "Q1 2026 planning meeting notes",
    metadata: {
      project: "acme-app",
      author: "dana",
      version: "1"
    }
  })
});

const data = await res.json();
console.log("CID:", data.cid);

Metadata memudahkan untuk menapis dan menyusun fail di pihak anda tanpa menghuraikan kandungan IPFS itu sendiri.

5. Pin CID sedia ada

Jika anda sudah mempunyai kandungan di IPFS dan ingin memastikan ia kekal tersedia, pin ia mengikut CID:

// pin-cid.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const res = await fetch(`${API}/pin`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY
  },
  body: JSON.stringify({
    cid: "bafkreigx7gq...",
    description: "Pinned from external source"
  })
});

const data = await res.json();
console.log("Pinned:", data.cid);

6. Senaraikan fail anda

Dapatkan setiap fail yang anda muat naik dalam tempoh masa tertentu. Parameter query from dan to ialah timestamp Unix dalam milisaat.

// list-files.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const now = Date.now();
const oneWeekAgo = now - 7 * 24 * 60 * 60 * 1000;

const url = `${API}/upload/list?from=${oneWeekAgo}&to=${now}`;

const res = await fetch(url, {
  headers: { "X-Api-Key": API_KEY }
});

const files = await res.json();

for (const file of files) {
  console.log(`${file.cid}  ${file.description ?? "(no description)"}`);
}

Dengan curl:

FROM=$(($(date +%s) * 1000 - 604800000))
TO=$(($(date +%s) * 1000))

curl -s "https://api.ipfs.ninja/upload/list?from=$FROM&to=$TO" \
  -H "X-Api-Key: bws_your_key_here" | jq .

7. Dapatkan butiran fail

Dapatkan rekod penuh untuk satu CID, termasuk metadata, saiz, dan timestamp:

// get-file.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const CID = "bafkreigx7gq...";

const res = await fetch(`${API}/file/${CID}`, {
  headers: { "X-Api-Key": API_KEY }
});

const details = await res.json();
console.log(JSON.stringify(details, null, 2));

8. Muat naik sebelah klien dengan token bertandatangan

Menyertakan kunci API dalam bundle pelayar adalah risiko keselamatan. Sebaliknya, jana token bertandatangan berumur pendek di pelayan anda dan hantarnya ke klien.

Pelayan (Express)

// server.mjs
import express from "express";

const app = express();
const API = "https://api.ipfs.ninja";
const API_KEY = process.env.IPFS_API_KEY;

app.post("/api/upload-token", async (req, res) => {
  const response = await fetch(`${API}/upload/signed-url`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Api-Key": API_KEY
    },
    body: JSON.stringify({
      name: "browser-upload",
      expiresIn: 600          // token valid for 10 minutes
    })
  });

  const { token, tokenId, expiresAt } = await response.json();
  res.json({ token, tokenId, expiresAt });
});

app.listen(3000, () => console.log("Server running on :3000"));

Klien pelayar

<!-- upload.html -->
<input type="file" id="filePicker" />
<button id="uploadBtn">Upload to IPFS</button>
<pre id="result"></pre>

<script>
  const API = "https://api.ipfs.ninja";

  document.getElementById("uploadBtn").addEventListener("click", async () => {
    // 1. Get a signed token from your own backend
    const tokenRes = await fetch("/api/upload-token", { method: "POST" });
    const { token } = await tokenRes.json();

    // 2. Read the selected file as base64
    const file = document.getElementById("filePicker").files[0];
    if (!file) return alert("Pick a file first");

    const base64 = await new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result.split(",")[1]);
      reader.readAsDataURL(file);
    });

    // 3. Upload directly to IPFS using the signed token
    const uploadRes = await fetch(`${API}/upload/new`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Signed ${token}`
      },
      body: JSON.stringify({
        content: base64,
        description: file.name
      })
    });

    const data = await uploadRes.json();
    document.getElementById("result").textContent = JSON.stringify(data, null, 2);
  });
</script>

Pelayar tidak pernah melihat kunci API anda. Token bertandatangan tamat tempoh secara automatik. Token boleh digunakan berkali-kali — boleh digunakan beberapa kali sehingga tamat tempoh atau dibatalkan. useCount dijejaki tetapi tidak dikuatkuasakan sebagai had.

9. Pengendalian ralat

API menggunakan kod status HTTP konvensional. Berikut adalah yang patut anda kendalikan secara eksplisit:

StatusMaksudApa yang perlu dilakukan
400Bad request — medan yang hilang atau tidak sahPeriksa content ada dan sah
401Unauthorized — kunci API yang salah atau hilangSahkan header X-Api-Key
413Payload too largeKurangkan saiz fail atau pisahkan kandungan
429Rate limitedBerundur dan cuba semula dengan kelewatan eksponen
500Server errorCuba semula selepas kelewatan singkat

Fungsi muat naik tahan dengan backoff eksponen:

// resilient-upload.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

async function uploadWithRetry(content, retries = 3) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    const res = await fetch(`${API}/upload/new`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Api-Key": API_KEY
      },
      body: JSON.stringify({ content })
    });

    if (res.ok) return await res.json();

    const body = await res.text();

    if (res.status === 401) {
      throw new Error(`Authentication failed: ${body}`);
    }

    if (res.status === 413) {
      throw new Error(`Payload too large — reduce file size. ${body}`);
    }

    if (res.status === 429 || res.status >= 500) {
      const delay = Math.pow(2, attempt) * 1000;    // 2s, 4s, 8s
      console.warn(`Attempt ${attempt} failed (${res.status}). Retrying in ${delay}ms...`);
      await new Promise((r) => setTimeout(r, delay));
      continue;
    }

    throw new Error(`Upload failed (${res.status}): ${body}`);
  }

  throw new Error("Upload failed after all retries");
}

// Usage
const data = await uploadWithRetry({ hello: "world" });
console.log("CID:", data.cid);

10. Contoh kerja yang lengkap

Satu skrip yang menjalankan setiap endpoint yang dilindungi dalam tutorial ini. Simpannya sebagai ipfs-demo.mjs dan jalankan dengan node ipfs-demo.mjs.

// ipfs-demo.mjs
import { readFileSync } from "node:fs";

const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";

const headers = {
  "Content-Type": "application/json",
  "X-Api-Key": API_KEY
};

async function request(method, path, body) {
  const opts = { method, headers };
  if (body) opts.body = JSON.stringify(body);
  const res = await fetch(`${API}${path}`, opts);
  if (!res.ok) throw new Error(`${method} ${path} → ${res.status}: ${await res.text()}`);
  return res.json();
}

// --- 1. Upload JSON ---
console.log("--- Upload JSON ---");
const jsonResult = await request("POST", "/upload/new", {
  content: { name: "Demo Token", edition: 1 },
  description: "Tutorial demo — JSON upload",
  metadata: { tutorial: "true" }
});
console.log("CID:", jsonResult.cid);
console.log("URL:", jsonResult.uris.url);

// --- 2. Upload an image (if photo.png exists) ---
try {
  const img = readFileSync("./photo.png");
  console.log("\n--- Upload Image ---");
  const imgResult = await request("POST", "/upload/new", {
    content: img.toString("base64"),
    description: "Tutorial demo — image upload"
  });
  console.log("CID:", imgResult.cid);
  console.log("URL:", imgResult.uris.url);
} catch {
  console.log("\n--- Skipping image upload (no photo.png found) ---");
}

// --- 3. Pin the JSON CID ---
console.log("\n--- Pin CID ---");
const pinResult = await request("POST", "/pin", {
  cid: jsonResult.cid,
  description: "Pinned from tutorial"
});
console.log("Pinned:", pinResult.cid);

// --- 4. Get file details ---
console.log("\n--- File Details ---");
const details = await request("GET", `/file/${jsonResult.cid}`);
console.log(JSON.stringify(details, null, 2));

// --- 5. List recent files ---
console.log("\n--- Recent Files ---");
const now = Date.now();
const oneHourAgo = now - 60 * 60 * 1000;
const files = await request("GET", `/upload/list?from=${oneHourAgo}&to=${now}`);
console.log(`Found ${files.length} file(s) in the last hour`);
for (const f of files) {
  console.log(` - ${f.cid}  ${f.description ?? ""}`);
}

// --- 6. Create a signed upload token ---
console.log("\n--- Signed Token ---");
const tokenResult = await request("POST", "/upload/signed-url", {
  name: "demo-token",
  expiresIn: 300
});
console.log("Token ID :", tokenResult.tokenId);
console.log("Expires  :", new Date(tokenResult.expiresAt).toISOString());

// --- 7. Upload using the signed token ---
console.log("\n--- Upload with Signed Token ---");
const signedRes = await fetch(`${API}/upload/new`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Signed ${tokenResult.token}`
  },
  body: JSON.stringify({
    content: { note: "Uploaded with a signed token" }
  })
});
const signedData = await signedRes.json();
console.log("CID:", signedData.cid);

console.log("\nDone.");

Ganti bws_your_key_here dengan kunci sebenar dan jalankan skrip. Setiap langkah mencetak keputusannya supaya anda boleh mengikuti.

11. Langkah seterusnya

Anda kini tahu cara memuat naik, mengepin, menyenarai, dan mendapatkan fail melalui IPFS Upload API dan cara memastikan muat naik pelayar selamat dengan token bertandatangan. Untuk gambaran keseluruhan yang lebih luas termasuk UI dashboard dan contoh Python, lihat Cara memuat naik fail ke IPFS. Berikut tempat untuk pergi dari sini:

  • API Reference — Dokumentasi endpoint lengkap di ipfs.ninja/docs.
  • Gateway tersuai — Sediakan kandungan IPFS dari domain anda sendiri. Lihat panduan persediaan gateway.
  • Analitik — Jejak isi padu muat naik, lebar jalur, dan kiraan pin di dashboard.
  • Klien HTTP — SDK tidak diperlukan. Anda boleh menggunakan fetch() standard atau mana-mana klien HTTP untuk berinteraksi dengan API.

Jika anda menghadapi masalah, buka tiket di support.ipfs.ninja atau sertai komuniti di Discord.

Kembali ke Blog

Artikel Berkaitan

Lihat Semua Artikel »