How to render image from IPFS using Next.js

I’m quite new in web3 and IPFS, trying to understand that technologies using a course with NFT Marketplace but it’s 2 years old, so I found some difficulties in case of deprecation ipfs-http-client: so I switch to kubo-rpc-client which has a quite similar functionality, and trying to use infura with that guide.

I solved the problem with loading an image on my dedicated gateway:

https://unsleeping.infura-ipfs.io/ipfs/

I have an example:

https://unsleeping.infura-ipfs.io/ipfs/QmQaQJiXTtgU8w4qhKDYmG9wEdDFLsVHFCyPZ5HVyYTATu

But I can’t render that image cuz of my error in Next.js app:

The requested resource isn’t a valid image for https://unsleeping.infura-ipfs.io/ipfs/QmQaQJiXTtgU8w4qhKDYmG9wEdDFLsVHFCyPZ5HVyYTATu received application/octet-stream`

I also tried MediaRenderer from @thirdweb-dev/react using this guide

with url like ipfs://, for example:

ipfs://QmeGAVddnBSnKc1DLE7DLV9uuTqo5F7QbaveTjr45JUdQn

Also using MediaRenderer I found out that image requested from .ipfs.cf-ipfs.com

like that https://bafybeihmstb4g5ns2hb77ixntytxskvpyzj2mzeu2k72dbnugqp2oj4epm.ipfs.cf-ipfs.com

but still on my Next.js app it has a white placeholder instead of an actual image.

I have a really simple question. How to render the image from file which stores on https://unsleeping.infura-ipfs.io/ipfs/

Can’t find any solution for that in 2023

2 Likes

okay, I found out that problem was on my side,
i’m using client side to send file on my api to get a secrets from .env to upload it on ipfs and didn’t handle files well, it worked like uploading a files not an images, then I changed the strategy to use formdata to send a file like this:

  const uploadToIPFS = async (file: File) => {
    try {
      const data = new FormData();
      data.append("name", "Image Upload");
      data.append("file_attachment", file);
      const response = await axios.post("/api/ipfs", data, {
        headers: {
          "Content-Type": "multipart/form-data;",
        },
      });
      return response.data.url;
    } catch (e) {
      console.error(`Error uploading file to IPFS: ${e}`);
    }
  };

and after that in pages/api/ipfs.ts

import { NextApiRequest, NextApiResponse } from "next";
import { create } from "kubo-rpc-client";
import { createReadStream } from "fs";
import { IncomingForm, File } from "formidable";

const {
  INFURA_PROJECT_ID,
  INFURA_PROJECT_SECRET,
} = process.env;

const auth = `Basic ${Buffer.from(
  `${INFURA_PROJECT_ID}:${INFURA_PROJECT_SECRET}`
).toString("base64")}`;

const client = create({
  host: "ipfs.infura.io",
  port: 5001,
  protocol: "https",
  headers: {
    authorization: auth,
  },
});
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    if (req.method !== "POST") {
      return res.status(405).json({ error: "Method Not Allowed" });
    }

    const form = new IncomingForm();

    form.parse(req, async (err, fields, files) => {
      if (err) {
        console.error(`Error parsing form data: ${err}`);
        return res.status(500).json({ error: "Internal Server Error" });
      }

      const fileAttachment = files.file_attachment as File[];

      if (!fileAttachment) {
        return res
          .status(400)
          .json({ error: "File not provided in the request" });
      }

      const added = await client.add(
        createReadStream(fileAttachment[0].filepath)
      );
      const url = `https://unsleeping.infura-ipfs.io/ipfs/${added.cid}`;

      res.status(200).json({ url });
    });
  } catch (error) {
    console.error(`Error handling file upload: ${error}`);
    res.status(500).json({ error: "Internal Server Error" });
  }
}

so it helps me to handle images well, now when i upload an image using kubo-rpc-client, i get the correct CID to an image, not a file, so i can easily use MediaRenderer now from thirdweb or use a common html image tag or Image from ‘next/image’

2 Likes

Hey @unsleeping , thanks for letting us know and for the details provided. Should you face other issues let us know and we’ll try to help.

2 Likes

This topic was automatically closed after 30 days. New replies are no longer allowed.