· Nacho Coll · Tutorials  · 11 phút đọc

IPFS Upload API — Hướng dẫn dành cho lập trình viên đầy đủ

Học cách tải tệp lên IPFS qua REST API. Các ví dụ mã hoàn chỉnh trong JavaScript, Node.js và curl. Tải JSON, hình ảnh, sử dụng token đã ký cho tải lên phía client.

Học cách tải tệp lên IPFS qua REST API. Các ví dụ mã hoàn chỉnh trong JavaScript, Node.js và curl. Tải JSON, hình ảnh, sử dụng token đã ký cho tải lên phía client.

IPFS Upload API — Hướng dẫn dành cho lập trình viên đầy đủ

Tải tệp lên IPFS phải đơn giản như thực hiện một yêu cầu POST. Trong hướng dẫn này, bạn sẽ làm chính xác điều đó — tải tài liệu JSON, hình ảnh, và PDF lên IPFS chỉ với fetch() và một khóa API. Ở cuối, bạn sẽ có một script Node.js hoàn chỉnh tải nội dung lên, liệt kê các tệp, lấy siêu dữ liệu, và tạo token đã ký cho tải lên phía client an toàn. Mới với IPFS? Bắt đầu với IPFS Pinning là gì? để hiểu các khái niệm cơ bản trước khi đi vào mã.

IPFS Ninja API keys management page

Những gì bạn sẽ xây dựng

  • Tải một đối tượng JSON lên IPFS và nhận lại một định danh nội dung (CID).
  • Tải lên một hình ảnh nhị phân từ đĩa.
  • Đính kèm mô tả và siêu dữ liệu tùy chỉnh vào các tải lên.
  • Truy vấn lịch sử tải lên của bạn theo phạm vi ngày.
  • Lấy chi tiết cho một tệp cụ thể.
  • Tạo token đã ký có giới hạn thời gian để trình duyệt có thể tải lên trực tiếp mà không tiết lộ khóa API của bạn.
  • Xử lý lỗi và triển khai logic thử lại.

Mọi thứ đều chạy đối với một URL cơ sở duy nhất: https://api.ipfs.ninja

1. Thiết lập — Đăng ký và lấy khóa API

  1. Đăng ký một tài khoản miễn phí (không cần thẻ tín dụng).
  2. Đi đến API Keys trong thanh bên dashboard.
  3. Nhấp vào Create key, đặt tên cho nó, và sao chép khóa ngay lập tức — nó sẽ không được hiển thị lại.
API Keys page — create and manage your keys

Khóa của bạn trông giống như bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6. Mỗi ví dụ bên dưới gửi nó trong header X-Api-Key.

2. Tải JSON lên IPFS

Tải lên đơn giản nhất: truyền một đối tượng JavaScript thuần như content và API sẽ serialize nó, pin nó lên IPFS, và trả về 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);

Chạy với node upload-json.mjs. Một phản hồi thành công trông như sau:

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

Trường url trỏ đến một gateway HTTP công khai, nên nội dung có thể truy cập ngay lập tức trên bất kỳ trình duyệt nào.

3. Tải lên một hình ảnh

Các tệp nhị phân (hình ảnh, PDF, âm thanh) được gửi dưới dạng chuỗi được mã hóa base64 trong trường 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 tự động phát hiện loại MIME — PNG, JPEG, WebP, GIF, và PDF đều được hỗ trợ. Không yêu cầu header thêm hoặc ghi đè content-type.

Với curl, cùng thao tác trông như sau:

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. Tải lên với siêu dữ liệu

Mỗi lần tải lên chấp nhận hai trường tùy chọn: description (nhãn văn bản tự do) và metadata (các cặp khóa-giá trị tùy ý). Cả hai đều được lưu trữ cùng với CID và được trả về khi bạn liệt kê hoặc tìm nạp tệp sau này.

// 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);

Siêu dữ liệu giúp dễ dàng lọc và sắp xếp các tệp ở phía bạn mà không cần phân tích cú pháp nội dung IPFS.

5. Pin một CID hiện có

Nếu bạn đã có nội dung trên IPFS và muốn đảm bảo nó vẫn có sẵn, hãy pin nó bằng 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. Liệt kê các tệp của bạn

Truy xuất mọi tệp bạn đã tải lên trong khoảng thời gian. Các tham số truy vấn fromtodấu thời gian Unix tính bằng mili giây.

// 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)"}`);
}

Với 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. Lấy chi tiết tệp

Tìm nạp bản ghi đầy đủ cho một CID duy nhất, bao gồm siêu dữ liệu, kích thước, và dấu thời gian:

// 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. Tải lên phía client với token đã ký

Nhúng khóa API vào gói trình duyệt là rủi ro bảo mật. Thay vào đó, hãy tạo một token đã ký ngắn hạn trên máy chủ của bạn và chuyển nó cho client.

Máy chủ (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"));

Client trình duyệt

<!-- 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>

Trình duyệt không bao giờ thấy khóa API của bạn. Token đã ký tự động hết hạn. Token có thể sử dụng nhiều lần — chúng có thể được sử dụng nhiều lần cho đến khi hết hạn hoặc bị thu hồi. useCount được theo dõi nhưng không được thực thi như một giới hạn.

9. Xử lý lỗi

API sử dụng mã trạng thái HTTP thông thường. Đây là những mã bạn nên xử lý rõ ràng:

StatusÝ nghĩaPhải làm gì
400Bad request — thiếu hoặc trường không hợp lệKiểm tra content có hiện diện và hợp lệ không
401Unauthorized — khóa API xấu hoặc thiếuXác minh header X-Api-Key
413Payload quá lớnGiảm kích thước tệp hoặc chia nội dung
429Giới hạn tốc độLùi lại và thử lại với độ trễ theo cấp số nhân
500Lỗi máy chủThử lại sau độ trễ ngắn

Một hàm tải lên có khả năng phục hồi với backoff theo cấp số nhân:

// 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. Ví dụ hoạt động đầy đủ

Một script duy nhất thực hiện mọi endpoint được đề cập trong hướng dẫn này. Lưu nó dưới dạng ipfs-demo.mjs và chạy bằng 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.");

Thay thế bws_your_key_here bằng một khóa thực và chạy script. Mỗi bước in ra kết quả của nó để bạn có thể theo dõi.

11. Các bước tiếp theo

Bây giờ bạn đã biết cách tải lên, pin, liệt kê, và truy xuất tệp qua IPFS Upload API và cách giữ an toàn cho tải lên trình duyệt với token đã ký. Để có cái nhìn rộng hơn bao gồm UI dashboard và ví dụ Python, xem Cách tải tệp lên IPFS. Đây là nơi để đi từ đây:

  • Tham chiếu API — Tài liệu endpoint đầy đủ tại ipfs.ninja/docs.
  • Gateway tùy chỉnh — Phục vụ nội dung IPFS từ tên miền của riêng bạn. Xem hướng dẫn thiết lập gateway.
  • Phân tích — Theo dõi khối lượng tải lên, băng thông, và số lượng pin trong dashboard.
  • HTTP client — Không cần SDK. Bạn có thể sử dụng fetch() tiêu chuẩn hoặc bất kỳ HTTP client nào để tương tác với API.

Nếu bạn gặp vấn đề, mở một vé tại support.ipfs.ninja hoặc tham gia cộng đồng trên Discord.

Quay lại Blog

Bài viết liên quan

Xem tất cả bài viết »