IPFS Pinata service not accepting file

Viewed 5284

I have a code as shown below that uploads files from the browser and saves in the server, once it has been saved to the server, I want the server to connect to the Pinata API so the file can also be saved to the IPFS node.

  let data = new FormData();

                      const fileBuffer = Buffer.from(`./public/files/${fileName}`, 'utf-8');
                      data.append('file', fileBuffer, `${fileName}`);

                      axios.post('https://api.pinata.cloud/pinning/pinJSONToIPFS',
                          data,
                          {
                              headers: {
                                  'Content-Type': `multipart/form-data; boundary= ${data._boundary}`,
                                  'pinata_api_key': pinataApiKey,
                                  'pinata_secret_api_key': pinataSecretApiKey
                              }
                          }
                      ).then(function (response) {
                          console.log("FILE UPLOADED TO IPFS NODE", fileName);
                          console.log(response);
                      }).catch(function (error) {
                          console.log("FILE WASNT UPLOADED TO IPFS NODE", fileName);
                          console.log(error);
                      });

The issue i'm having is that after creating a buffer of my file and wrapping it in a formdata, the pinata API returns an error :

   data: {
      error: 'This API endpoint requires valid JSON, and a JSON content-type'
    }

If i convert the data to string like JSON.stringify(data) and change the content-type to application/json, the file buffer will be uploaded successfully as string.

I hope explained it well to get a solution. Thanks.

4 Answers

It looks like you're attempting to upload a file to the pinJSONToIPFS endpoint, which is intended to purely be used for JSON that is passed in via a request body.

In your situation I would recommend using Pinata's pinFileToIPFS endpoint

Here's some example code based on their documentation that may be of help:

//imports needed for this function
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');

export const pinFileToIPFS = (pinataApiKey, pinataSecretApiKey) => {
    const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;

    //we gather a local file for this example, but any valid readStream source will work here.
    let data = new FormData();
    data.append('file', fs.createReadStream('./yourfile.png'));

    return axios.post(url,
        data,
        {
            maxContentLength: 'Infinity', //this is needed to prevent axios from erroring out with large files
            headers: {
                'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
                'pinata_api_key': pinataApiKey,
                'pinata_secret_api_key': pinataSecretApiKey
            }
        }
    ).then(function (response) {
        //handle response here
    }).catch(function (error) {
        //handle error here
    });
};

The proper code to pin any file to IPFS is as below.

Apparently, even Pinata support staff didn't know this. You need to set an object with the property name filepath as your last parameter. The name doesn't matter, it can be a duplicate, it can be the same as others, or it can be unique.

const url = "https://api.pinata.cloud/pinning/pinFileToIPFS";
const fileContents = Buffer.from(bytes);
const data = new FormData();
data.append("file", fileContents, {filepath: "anyname"});
const result = await axios
    .post(url, data, {
        maxContentLength: -1,
        headers: {
            "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
            "pinata_api_key": userApiKey,
            "pinata_secret_api_key": userApiSecret,
            "path": "somename"
        }
    });

Code to upload a file on IPFS using Pinata.

There are two methods available to upload files/images on Pinata. One is with Pinata SDK and the second is the pinFileToIPFS endpoint.

If you are uploading files from Next.js then you cannot convert your image into binary using fs.createReadStream or Buffer.from. These packages support the Node side. So if you want to upload the file with Next.js on Pinata then you can use this code.

 // convert file into binary
      const data = new FormData();
      data.append("title", file.name);
      data.append("file", file);

     const url = "https://api.pinata.cloud/pinning/pinFileToIPFS";
        // pass binary data into post request
        const result = await axios.post(url, data, {
          maxContentLength: -1,
          headers: {
            "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
            pinata_api_key: "your_pinata_key",
            pinata_secret_api_key:
              "your_pinata_secret",
            path: "somename",
          },
        });
        console.log("RESULT", result);

this will upload a file to ipfs under the path ipfs://{cid}/images/{fileId}

    const PINATA_BASE_URL = "https://api.pinata.cloud";
    const PINATA_PIN_URI = "/pinning/pinFileToIPFS";

    const fileExt = file.type.split("/")[1];
    
    let nftId = 1
    
    // creates a 64byte string '0000...0001' to follow ERC-1155 standard
    const paddedId = createPaddedHex(nftId);

    const ipfsFileId = `${paddedId}.${fileExt}`;

    const ipfsImageFilePath = `/images/${ipfsFileId}`;

    const fileUploadData = new FormData();

    // this uploads the file and renames the uploaded file to the path created above
    fileUploadData.append("file", file, ipfsImageFilePath);
    fileUploadData.append(
      "pinataOptions",
      '{"cidVersion": 1, "wrapWithDirectory": true}'
    );
    fileUploadData.append(
      "pinataMetadata",
      `{"name": "${ipfsImageFilePath}", "keyvalues": {"company": "Pinata"}}`
    );

    const pinataUploadRes = await axios.post(
      PINATA_BASE_URL + PINATA_PIN_URI,
      fileUploadData,
      {
        headers: {
          Authorization: `Bearer ${PINATA_JWT}`,
        },
      }
    );

    const ipfsCID = pinataUploadRes.data.IpfsHash;
Related