Skip to content

S3-compatibiliteit

Gebruik de AWS SDK om bestanden te uploaden, downloaden en beheren op IPFS Ninja met dezelfde code die je voor Amazon S3 gebruikt.

Endpoint

https://s3.ipfs.ninja

Inloggegevens

De S3 API gebruikt je IPFS Ninja API-sleutel voor authenticatie. Je API-sleutel dient zowel als toegangssleutel als geheime sleutel.

Hoe je je inloggegevens verkrijgt

  1. Ga naar Dashboard > API Keys
  2. Klik op Create API key en geef deze een naam (bijv. "S3 access")
  3. Kopieer de volledige sleutel onmiddellijk — deze wordt slechts eenmaal getoond en kan later niet worden opgehaald

Je sleutel ziet er zo uit:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 prefix (12 chars)    rest of key

Toewijzing aan AWS-parameters

AWS-parameterWaardeVoorbeeld
accessKeyIdDe eerste 12 tekens van je API-sleutelbws_628bba35
secretAccessKeyDe volledige API-sleutel (alle 36 tekens)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionAltijd us-east-1us-east-1

WARNING

De volledige API-sleutel wordt slechts eenmaal getoond wanneer je deze aanmaakt. Als je hem kwijtraakt, verwijder de sleutel en maak een nieuwe aan op de API Keys-pagina.

Snelstart

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Buckets = mappen

S3-buckets komen overeen met je IPFS Ninja-mappen. Wanneer je een bestand uploadt naar een bucket, wordt het opgeslagen in de bijbehorende map. Wanneer je objecten in een bucket oplijst, zie je de bestanden in die map.

S3-operatieIPFS Ninja-equivalent
CreateBucketEen nieuwe map aanmaken
ListBucketsJe mappen oplijsten
DeleteBucketEen map en alle bestanden erin verwijderen
PutObject naar bucketBestand uploaden naar de map
ListObjectsV2 op bucketBestanden in de map oplijsten
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

Mappen die via de S3 API zijn aangemaakt, zijn dezelfde mappen die zichtbaar zijn in je Dashboard. Je kunt bestanden organiseren via de S3 API, de REST API of de webinterface — ze delen allemaal hetzelfde mappensysteem.

INFO

In tegenstelling tot Amazon S3 zijn IPFS Ninja-mappen standaard plat. Om geneste structuren aan te maken, gebruik je de mappenendpoints van de REST API met parentFolderId. Via de S3 API kun je sleutelprefixen gebruiken (bijv. images/photo.png) om bestanden binnen een map te ordenen.

Bucketnamen zijn wereldwijd uniek

Bucketnamen leven in een globale namespace over alle klanten heen, conform de AWS S3-semantiek. Dat betekent:

  • De eerste gebruiker die een bucket met een bepaalde naam aanmaakt, claimt die naam wereldwijd.
  • Latere CreateBucket-aanroepen met dezelfde naam vanuit elk account geven BucketAlreadyExists (409) terug.
  • Als je probeert je eigen bucket opnieuw aan te maken, krijg je BucketAlreadyOwnedByYou (409).
  • Je mapnaam in het dashboard is per account en kan nog steeds alles zijn — alleen de S3-zichtbare bucketnaam gaat door de globale namespace.

Als een gewenste naam al bezet is, kies dan een naam met een andere scope (myapp-photos-2026, acme-nft-metadata) — dezelfde conventie die je op Amazon S3 zou gebruiken.

Ondersteunde operaties

PutObject

Upload een bestand naar IPFS. Het bestand wordt vastgezet, op veiligheid gecontroleerd en de CID wordt geretourneerd in de ETag- en x-amz-meta-cid-headers.

Om in plaats daarvan een CAR-bestand te importeren, voeg je de metadata-header x-amz-meta-import: car toe. Zie CAR-import voor details.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# curl equivalent
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Download een bestand op basis van sleutel (bestandsnaam) of CID.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Verkrijg bestandsmetadata zonder de content te downloaden.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Zet een bestand los van IPFS en verwijder het van je account.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Lijst bestanden in een bucket op met optionele prefixfiltering en paginering.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Multipart-upload

Upload grote bestanden (tot 5 GB) met behulp van multipart-upload. De AWS SDK handelt dit automatisch af:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB per part
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

Of beheer de delen handmatig:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Start
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Upload parts
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Complete
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Python-voorbeeld

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Go-voorbeeld

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

CORS configureren (toegang via browser-SDK)

Als je de S3 API rechtstreeks vanuit browser-JavaScript aanroept (SPA, wallet-app, dashboardtool), moet je eerst CORS op de bucket configureren. Anders blokkeren browsers de preflight en mislukken je uploads met No 'Access-Control-Allow-Origin' header is present.

Zelfde vorm als AWS S3 — subresources PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Limiet en standaardwaarden

  • Tot 5 regels per bucket (de spec staat 100 toe; wij hanteren een limiet van 5 om de preflight-respons van de browser compact te houden).
  • Totale configuratie beperkt tot 64 KB geserialiseerd.
  • Als er geen CORS-configuratie is ingesteld, worden browser-preflights geweigerd — conform de standaardhouding van AWS S3. Configureer expliciete regels voor de origins waar je daadwerkelijk vanaf serveert.

Praktische veiligheidsopmerking

CORS is een gemaksfunctie aan de browserzijde, geen beveiligingsgrens. Elke S3 API-aanroep vereist nog steeds een geldige SigV4-handtekening berekend vanuit je API-sleutel — een ruime CORS-configuratie laat niemand toe je bucket te gebruiken zonder die credential. Wat CORS wel voorkomt: dat een onbedoelde origin (bijv. een verouderde kopie van je app op dev.myapp.com) ondertekende verzoeken vanuit een browsercontext verstuurt.

Dashboard-alternatief

De pagina Bestanden heeft een S3 CORS-item in het actiemenu van elke map. Zelfde onderliggende opslag; als je geen PutBucketCors-code wilt schrijven, configureer je het daar.

Verschillen met Amazon S3

FunctieAmazon S3IPFS Ninja S3
OpslagmodelAanpasbare objectenContent-geadresseerd (onveranderlijke CID's)
OverschrijfgedragVervangt object ter plekkeMaakt nieuwe CID, oude CID blijft toegankelijk
VersiebeheerOndersteundNiet ondersteund (gebruik CID's voor versiebeheer)
Server-side versleutelingOndersteundNiet ondersteund (content staat op IPFS)
LevenscyclusbeleidOndersteundNiet ondersteund
Bucketbeleid / ACL'sOndersteundGebruik gateway-toegangsmodi
Vooraf ondertekende URL'sOndersteundGebruik ondertekende upload-tokens
Maximale objectgrootte5 TB5 GB (multipart), 100 MB (enkele PUT)
Regio'sMeerdere regio'sAlleen us-east-1
ETag-waardeMD5-hashIPFS-CID
Extra headersStandaard S3x-amz-meta-cid (IPFS-CID)
CID-formaatN.v.t.Moderne CIDv1 (bafy…) voor nieuwe uploads; legacy Qm… blijft geldig als invoer
Bucket-namespaceGlobaal (AWS-breed)Globaal (over alle IPFS Ninja-accounts) — zelfde semantiek
CORSPutBucketCors ondersteundPutBucketCors ondersteund (limiet van 5 regels)

Migreren vanaf Amazon S3

Vervang je S3-clientconfiguratie:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

Je bestaande PutObject-, GetObject-, ListObjectsV2- en DeleteObject-aanroepen werken ongewijzigd.

Migreren vanaf Filebase

Vervang de endpoint-URL:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });