· Nacho Coll · Tutorials  · 9 мин читања

IPFS Upload API — Kompletan tutorijal za programere

Naučite da otpremate fajlove na IPFS putem REST API-ja. Kompletni primeri koda u JavaScript-u, Node.js-u i curl-u. Otpremajte JSON, slike, koristite potpisane tokene za otpremanja sa klijenta.

Naučite da otpremate fajlove na IPFS putem REST API-ja. Kompletni primeri koda u JavaScript-u, Node.js-u i curl-u. Otpremajte JSON, slike, koristite potpisane tokene za otpremanja sa klijenta.

IPFS Upload API — Kompletan tutorijal za programere

Otpremanje fajlova na IPFS bi trebalo da bude jednostavno kao slanje POST zahteva. U ovom tutorijalu uradićete upravo to — otpremićete JSON dokumente, slike i PDF fajlove na IPFS sa ničim više od fetch() i API ključa. Na kraju ćete imati kompletnu Node.js skriptu koja otprema sadržaj, lista fajlove, dohvata metapodatke i generiše potpisane tokene za bezbedna otpremanja sa strane klijenta. Novi ste na IPFS-u? Počnite sa Šta je IPFS Pinning? da biste razumeli osnove pre nego što zaronite u kod.

IPFS Ninja API keys management page

Šta ćete izgraditi

  • Otpremićete JSON objekat na IPFS i dobiti nazad identifikator sadržaja (CID).
  • Otpremićete binarnu sliku sa diska.
  • Priložićete opise i prilagođene metapodatke otpremanjima.
  • Upitaćete svoju istoriju otpremanja po opsegu datuma.
  • Dohvatićete detalje za određeni fajl.
  • Kreiraćete vremenski ograničene potpisane tokene tako da pregledač može otpremati direktno bez izlaganja vašeg API ključa.
  • Rukovaćete greškama i implementiraćete logiku ponavljanja.

Sve se izvršava protiv jedne osnovne URL: https://api.ipfs.ninja

1. Podešavanje — Registracija i dobijanje API ključa

  1. Registrujte se za besplatan nalog (kreditna kartica nije potrebna).
  2. Idite na API Keys u bočnoj traci kontrolne table.
  3. Kliknite na Create key, dajte mu ime i odmah kopirajte ključ — neće se ponovo prikazati.
API Keys page — create and manage your keys

Vaš ključ izgleda ovako: bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6. Svaki primer ispod ga šalje u zaglavlju X-Api-Key.

2. Otpremanje JSON-a na IPFS

Najjednostavnije otpremanje: prosledite običan JavaScript objekat kao content i API ga serijalizuje, prikači na IPFS i vraća 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);

Pokrenite sa node upload-json.mjs. Uspešan odgovor izgleda ovako:

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

Polje url upućuje na javni HTTP gateway, tako da je sadržaj odmah dostupan u bilo kom pregledaču.

3. Otpremanje slike

Binarni fajlovi (slike, PDF-ovi, audio) šalju se kao base64-kodirani nizovi u polju 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 automatski detektuje MIME tip — PNG, JPEG, WebP, GIF i PDF su svi podržani. Dodatna zaglavlja ili poništavanja content-type nisu potrebni.

Sa curl-om ista operacija izgleda ovako:

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. Otpremanje sa metapodacima

Svako otpremanje prihvata dva opciona polja: description (oznaka slobodnog teksta) i metadata (proizvoljni parovi ključ-vrednost). Oba se čuvaju uz CID i vraćaju kada kasnije izlistate ili dohvatite fajl.

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

Metapodaci olakšavaju filtriranje i organizaciju fajlova na vašoj strani bez raščlanjivanja samog IPFS sadržaja.

5. Prikačivanje postojećeg CID-a

Ako već imate sadržaj na IPFS-u i želite da osigurate da ostane dostupan, prikačite ga po CID-u:

// 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. Izlistavanje vaših fajlova

Dohvatite svaki fajl koji ste otpremili u okviru vremenskog prozora. Query parametri from i to su Unix timestampi u milisekundama.

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

Sa curl-om:

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. Detalji fajla

Dohvatite kompletan zapis za jedan CID, uključujući metapodatke, veličinu i timestampe:

// 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. Otpremanja sa klijenta uz potpisane tokene

Ugrađivanje API ključa u browser bundle predstavlja bezbednosni rizik. Umesto toga, generišite kratkotrajni potpisani token na svom serveru i prosledite ga klijentu.

Server (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"));

Klijent u pregledaču

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

Pregledač nikada ne vidi vaš API ključ. Potpisani token automatski ističe. Tokeni su za višestruku upotrebu — mogu se koristiti više puta dok ne isteknu ili budu opozvani. useCount se prati, ali se ne primenjuje kao ograničenje.

9. Rukovanje greškama

API koristi konvencionalne HTTP statusne kodove. Evo onih koje biste trebali eksplicitno da obrađujete:

StatusZnačenjeŠta uraditi
400Bad request — polja koja nedostaju ili su nevažećaProverite da li je content prisutan i validan
401Unauthorized — pogrešan ili nepostojeći API ključProverite zaglavlje X-Api-Key
413Payload too largeSmanjite veličinu fajla ili podelite sadržaj
429Rate limitedSačekajte i pokušajte ponovo sa eksponencijalnim kašnjenjem
500Server errorPokušajte ponovo nakon kratkog kašnjenja

Otporna funkcija otpremanja sa eksponencijalnim backoff-om:

// 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. Kompletan radni primer

Jedna skripta koja vežba svaki endpoint pokriven u ovom tutorijalu. Sačuvajte je kao ipfs-demo.mjs i pokrenite sa 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.");

Zamenite bws_your_key_here pravim ključem i pokrenite skriptu. Svaki korak ispisuje svoj rezultat tako da možete da pratite.

11. Sledeći koraci

Sada znate kako da otpremate, kačite, listate i dohvatate fajlove kroz IPFS Upload API i kako da zadržite pregledačka otpremanja bezbedna sa potpisanim tokenima. Za širi pregled koji uključuje UI kontrolne table i Python primere, pogledajte Kako otpremiti fajlove na IPFS. Evo gde da krenete odavde:

  • API Reference — Kompletna dokumentacija endpointa na ipfs.ninja/docs.
  • Prilagođeni gateway-i — Servirajte IPFS sadržaj sa svog domena. Pogledajte vodič za podešavanje gateway-a.
  • Analitika — Pratite obim otpremanja, propusnost i broj kačenja u kontrolnoj tabli.
  • HTTP klijent — Nije potreban nijedan SDK. Možete koristiti standardni fetch() ili bilo kog HTTP klijenta za interakciju sa API-jem.

Ako naiđete na probleme, otvorite tiket na support.ipfs.ninja ili se pridružite zajednici na Discord-u.

Назад на Блог

Повезани чланци

Погледајте све чланке »