<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Atoo</title>
        <link>https://paragraph.com/@atoo</link>
        <description>undefined</description>
        <lastBuildDate>Wed, 19 Aug 2026 01:36:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Atoo</title>
            <url>https://storage.googleapis.com/papyrus_images/b2bfbbcdb776bcd8b90adcaee4da4370accca2610e675c2cc5dece725a94194e.png</url>
            <link>https://paragraph.com/@atoo</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Upload a file to Pinata: Using Next.js]]></title>
            <link>https://paragraph.com/@atoo/upload-a-file-to-pinata-using-next-js</link>
            <guid>djcYkgXfiZVhUZh7a9t6</guid>
            <pubDate>Mon, 09 Jan 2023 15:00:53 GMT</pubDate>
            <description><![CDATA[Upload a file to PinataHello everyone 👋, I, Atharva Deshpande am back with another article. This article focuses on creating a very simple app that uploads files to IPFS using Next.js. Here is the link to GitHub Repository. You can go ahead and get the code directly but I would recommend reading through the article once.PrerequisitesBasic knowledge of Blockchain and IPFS.Any code editor. ( I would be using VSCode )Basic understanding of JavascriptMachine with NodeJS installed.IntroductionIPF...]]></description>
            <content:encoded><![CDATA[<h1 id="h-upload-a-file-to-pinata" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Upload a file to Pinata</h1><p>Hello everyone 👋, I, Atharva Deshpande am back with another article. This article focuses on creating a very simple app that uploads files to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ipfs.tech/">IPFS</a> using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nextjs.org/">Next.js</a>.</p><p>Here is the link to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Atoo35/pinata-file-uploader">GitHub Repository</a>. You can go ahead and get the code directly but I would recommend reading through the article once.</p><h1 id="h-prerequisites" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Prerequisites</h1><ul><li><p>Basic knowledge of Blockchain and IPFS.</p></li><li><p>Any code editor. ( I would be using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code.visualstudio.com/download"><strong>VSCode</strong></a> )</p></li><li><p>Basic understanding of Javascript</p></li><li><p>Machine with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nodejs.org/en/"><strong>NodeJS</strong></a> installed.</p></li></ul><h1 id="h-introduction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h1><h3 id="h-ipfs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">IPFS</h3><p>IPFS is a way of storing and sharing files on the internet in a decentralized way. Instead of using a single server or central authority to host files, IPFS uses a network of computers to store and distribute files. This means that anyone can access and share files on the network without needing to go through a central server or authority. IPFS also uses a special kind of addressing system, which means that files are identified by their content, rather than by their location. This makes it possible to access files on the network without knowing where they are stored, which can make it more efficient and resilient than other ways of storing and sharing files online.</p><h1 id="h-lets-buidl-it" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Let&apos;s BUIDL It 🛠️</strong></h1><h3 id="h-step-1-pinata-account-setup" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 1: Pinata Account Setup</h3><ul><li><p>Head over to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.pinata.cloud/">Pinata</a> and create an account</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/35d793c4312668302c8bc34b5f6c76f045ab921d4fac1260a5d9fe628815bcd0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>Login to the account and click on &quot;Developers&quot; on the top NavBar.</p></li><li><p>Click on &quot;New Key&quot;, create an API key and copy the secret as you will not be able to look at the secret again.</p></li></ul><h3 id="h-step-2-write-some-code" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 2: Write some code 💻</h3><ul><li><p>Type in the command below in the terminal.</p><blockquote><p>Note: <code>pinata-uploader</code> is the name of the project that I have put. You can put it anything you like.</p></blockquote><pre data-type="codeBlock" text="npx create-next-app@latest pinata-uploader
"><code>npx create<span class="hljs-operator">-</span>next<span class="hljs-operator">-</span>app@latest pinata<span class="hljs-operator">-</span>uploader
</code></pre><p>Select &quot;No&quot; when the prompt asks you for using Typescript in the project and hit enter.</p><p>This is how your terminal would look after successful creation of the Next.js project.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9b81952bbb430962915bbc0f84ac192cf35755c619667e53b0c8f49f7f339246.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>Open the project in VSCode using the command</p><pre data-type="codeBlock" text="code pinata-uploader
"><code><span class="hljs-selector-tag">code</span> pinata-uploader
</code></pre><p>By running the command <code>npm run dev</code> you should be able to see the default UI provided by Next.js at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://localhost:3000">localhost</a>.</p></li><li><p>Create a <code>.env</code> file in the root of your project and put in your API key and API Secret as below.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/65d5bffedaa6ea65db824f8b17e7249a109cf2fa6f86d17fd0567a38473eeb2f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p>Save the file and head over to <code>next.config.js</code> in the root folder and replace it with the following.</p><pre data-type="codeBlock" text="/** @type {import(&apos;next&apos;).NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  env: {
    API_KEY: process.env.API_KEY,
    API_SECRET: process.env.API_SECRET
  }
}

module.exports = nextConfig
"><code><span class="hljs-comment">/** @type {import('next').NextConfig} */</span>
const nextConfig <span class="hljs-operator">=</span> {
  reactStrictMode: <span class="hljs-literal">true</span>,
  env: {
    API_KEY: process.env.API_KEY,
    API_SECRET: process.env.API_SECRET
  }
}

module.exports <span class="hljs-operator">=</span> nextConfig
</code></pre><blockquote><p>NOTE: Don&apos;t forget to load these env variables using the command <code>source ./.env</code> in Linux/macOS terminal.</p></blockquote><p>Finally, we would be now writing the main code which deals with Pinata.</p></li><li><p>Go to <code>pages/index.js</code> and replace the <code>Home</code> function with the following</p></li></ul><pre data-type="codeBlock" text="export default function Home() {
  return (
    &lt;div className={styles.container}&gt;
      &lt;input type=&apos;file&apos; onChange={(e)=&gt;setFile(e.target.files[0])}&gt;&lt;/input&gt;
      &lt;button onClick={handleUpload}&gt;Upload&lt;/button&gt;
      &lt;ul&gt;
        {
          pinnedFiles &amp;&amp; pinnedFiles.map(file =&gt; (
            &lt;li key={file.id}&gt;
              &lt;a href={`https://gateway.pinata.cloud/ipfs/${file.ipfs_pin_hash}`} target=&apos;_blank&apos; rel=&apos;noreferrer&apos;&gt;{file.metadata.name}&lt;/a&gt;
            &lt;/li&gt;
          ))
          
        }
      &lt;/ul&gt;
    &lt;/div&gt;
  )
}
"><code>export default <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>div className<span class="hljs-operator">=</span>{styles.container}<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">'file'</span> onChange<span class="hljs-operator">=</span>{(e)<span class="hljs-operator">=</span><span class="hljs-operator">></span>setFile(e.target.files[<span class="hljs-number">0</span>])}<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>input<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{handleUpload}<span class="hljs-operator">></span>Upload<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ul<span class="hljs-operator">></span>
        {
          pinnedFiles <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> pinnedFiles.map(file <span class="hljs-operator">=</span><span class="hljs-operator">></span> (
            <span class="hljs-operator">&#x3C;</span>li key<span class="hljs-operator">=</span>{file.id}<span class="hljs-operator">></span>
              <span class="hljs-operator">&#x3C;</span>a href<span class="hljs-operator">=</span>{`https:<span class="hljs-comment">//gateway.pinata.cloud/ipfs/${file.ipfs_pin_hash}`} target='_blank' rel='noreferrer'>{file.metadata.name}&#x3C;/a></span>
            <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>li<span class="hljs-operator">></span>
          ))
          
        }
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>ul<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
  )
}
</code></pre><p>On saving the file you will get some error related to <code>handleUpload</code> function not existing. Let&apos;s fix that:</p><p>Write a simple function defition which does nothing</p><pre data-type="codeBlock" text="const handleUpload = async () =&gt; {
}
"><code><span class="hljs-keyword">const</span> <span class="hljs-title function_">handleUpload</span> = <span class="hljs-keyword">async</span> (<span class="hljs-params"></span>) => {
}
</code></pre><p>When you save this, you will get another error. Add the following line to solve it</p><pre data-type="codeBlock" text="const [pinnedFiles, setPinnedFiles] = useState([])
"><code>const <span class="hljs-selector-attr">[pinnedFiles, setPinnedFiles]</span> = <span class="hljs-built_in">useState</span>([])
</code></pre><p>You should now be able to see a very bad UI with a simple upload button and file selector.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/10286c31b4f5115fba0553c317cc62743c1c58cc390509b5be5889f3181445c5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Let&apos;s make these things work.</p><ul><li><p>Since we would be dealing with Pinata APIs, we would need to install <code>axios</code> by typing the command <code>npm i --save axios</code></p></li><li><p>Define a Pinata Config variable like this</p><pre data-type="codeBlock" text="const pinataConfig = {
    root: &apos;https://api.pinata.cloud&apos;,
    headers: { 
      &apos;pinata_api_key&apos;: process.env.API_KEY,
      &apos;pinata_secret_api_key&apos;: process.env.API_SECRET
    }
};
"><code>const pinataConfig <span class="hljs-operator">=</span> {
    root: <span class="hljs-string">'https://api.pinata.cloud'</span>,
    headers: { 
      <span class="hljs-string">'pinata_api_key'</span>: process.env.API_KEY,
      <span class="hljs-string">'pinata_secret_api_key'</span>: process.env.API_SECRET
    }
};
</code></pre></li><li><p>Create a test function to check if we are indeed able to make the API call.</p></li></ul><pre data-type="codeBlock" text="const testPinataConnection = async() =&gt; {
    try {
      const url =`${pinataConfig.root}/data/testAuthentication`
      const res = await axios.get(url, {headers: pinataConfig.headers});
      console.log(res.data);
    } catch (error) {
      console.log(error)
    }
}
"><code>const testPinataConnection <span class="hljs-operator">=</span> async() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">try</span> {
      const url <span class="hljs-operator">=</span>`${pinataConfig.root}<span class="hljs-operator">/</span>data<span class="hljs-operator">/</span>testAuthentication`
      const res <span class="hljs-operator">=</span> await axios.get(url, {headers: pinataConfig.headers});
      console.log(res.data);
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-function"><span class="hljs-keyword">error</span>)
    }
}
</span></code></pre><p>Call this function on page load using the <code>useEffect</code> function.</p><pre data-type="codeBlock" text="useEffect(() =&gt; {
    testPinataConnection()
});
"><code><span class="hljs-built_in">useEffect</span>(() => {
    <span class="hljs-built_in">testPinataConnection</span>()
});
</code></pre><p>Open the developer tools and head over to console to see a success message from pinata. If you don&apos;t see any message then recheck all the steps we did above very carefully.</p><p>By far, your <code>index.js</code> should look like this</p><pre data-type="codeBlock" text="import Head from &apos;next/head&apos;
import Image from &apos;next/image&apos;
import { useEffect, useState } from &apos;react&apos;
import styles from &apos;../styles/Home.module.css&apos;
import axios from &apos;axios&apos;

export default function Home () {
  const [pinnedFiles, setPinnedFiles] = useState([])
  const [file, setFile] = useState(null)
  const handleUpload = async () =&gt; {
  }

  const pinataConfig = {
    root: &apos;https://api.pinata.cloud&apos;,
    headers: {
      &apos;pinata_api_key&apos;: process.env.API_KEY,
      &apos;pinata_secret_api_key&apos;: process.env.API_SECRET
    }
  };

  const testPinataConnection = async () =&gt; {
    try {
      console.log(pinataConfig)
      const url = `${pinataConfig.root}/data/testAuthentication`
      const res = await axios.get(url, { headers: pinataConfig.headers });
      console.log(res.data);
    } catch (error) {
      console.log(error)
    }
  }

  useEffect(() =&gt; {
    testPinataConnection()
  });

  return (
    &lt;div className={styles.container}&gt;
      &lt;input type=&apos;file&apos; onChange={(e) =&gt; setFile(e.target.files[0])}&gt;&lt;/input&gt;
      &lt;button onClick={handleUpload}&gt;Upload&lt;/button&gt;
      &lt;ul&gt;
        {
          pinnedFiles &amp;&amp; pinnedFiles.map(file =&gt; (
            &lt;li key={file.id}&gt;
              &lt;a href={`https://gateway.pinata.cloud/ipfs/${file.ipfs_pin_hash}`} target=&apos;_blank&apos; rel=&apos;noreferrer&apos;&gt;{file.metadata.name}&lt;/a&gt;
            &lt;/li&gt;
          ))

        }
      &lt;/ul&gt;
    &lt;/div&gt;
  )
}
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">Head</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'next/head'</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">Image</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'next/image'</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> { <span class="hljs-title">useEffect</span>, <span class="hljs-title">useState</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">styles</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../styles/Home.module.css'</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">axios</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'axios'</span>

<span class="hljs-title">export</span> <span class="hljs-title">default</span> <span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">Home</span> () {
  <span class="hljs-title">const</span> [<span class="hljs-title">pinnedFiles</span>, <span class="hljs-title">setPinnedFiles</span>] <span class="hljs-operator">=</span> <span class="hljs-title">useState</span>([])
  <span class="hljs-title">const</span> [<span class="hljs-title">file</span>, <span class="hljs-title">setFile</span>] <span class="hljs-operator">=</span> <span class="hljs-title">useState</span>(<span class="hljs-title">null</span>)
  <span class="hljs-title">const</span> <span class="hljs-title">handleUpload</span> <span class="hljs-operator">=</span> <span class="hljs-title">async</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  }

  <span class="hljs-title">const</span> <span class="hljs-title">pinataConfig</span> <span class="hljs-operator">=</span> {
    <span class="hljs-title">root</span>: <span class="hljs-string">'https://api.pinata.cloud'</span>,
    <span class="hljs-title">headers</span>: {
      <span class="hljs-string">'pinata_api_key'</span>: <span class="hljs-title">process</span>.<span class="hljs-title">env</span>.<span class="hljs-title">API_KEY</span>,
      <span class="hljs-string">'pinata_secret_api_key'</span>: <span class="hljs-title">process</span>.<span class="hljs-title">env</span>.<span class="hljs-title">API_SECRET</span>
    }
  };

  const testPinataConnection <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">try</span> {
      console.log(pinataConfig)
      const url <span class="hljs-operator">=</span> `${pinataConfig.root}<span class="hljs-operator">/</span>data<span class="hljs-operator">/</span>testAuthentication`
      const res <span class="hljs-operator">=</span> await axios.get(url, { headers: pinataConfig.headers });
      console.log(res.data);
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-function"><span class="hljs-keyword">error</span>)
    }
  }

  <span class="hljs-title">useEffect</span>(<span class="hljs-params">(<span class="hljs-params"></span>) => {
    testPinataConnection(<span class="hljs-params"></span>)
  }</span>)</span>;

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>div className<span class="hljs-operator">=</span>{styles.container}<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">'file'</span> onChange<span class="hljs-operator">=</span>{(e) <span class="hljs-operator">=</span><span class="hljs-operator">></span> setFile(e.target.files[<span class="hljs-number">0</span>])}<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>input<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{handleUpload}<span class="hljs-operator">></span>Upload<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>ul<span class="hljs-operator">></span>
        {
          pinnedFiles <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> pinnedFiles.map(file <span class="hljs-operator">=</span><span class="hljs-operator">></span> (
            <span class="hljs-operator">&#x3C;</span>li key<span class="hljs-operator">=</span>{file.id}<span class="hljs-operator">></span>
              <span class="hljs-operator">&#x3C;</span>a href<span class="hljs-operator">=</span>{`https:<span class="hljs-comment">//gateway.pinata.cloud/ipfs/${file.ipfs_pin_hash}`} target='_blank' rel='noreferrer'>{file.metadata.name}&#x3C;/a></span>
            <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>li<span class="hljs-operator">></span>
          ))

        }
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>ul<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
  )
}
</code></pre><p>Now let&apos;s get to adding the functionality of actually uploading a file to IPFS. We will update the <code>handleUpload</code> function to this.</p><pre data-type="codeBlock" text="  const handleUpload = async () =&gt; {
    try {
      if (file !== undefined) {
        const formData = new FormData();
        console.log(file)
        formData.append(&apos;file&apos;, file);
        const pinataBody = {
          options: {
            cidVersion: 1,
          },
          metadata: {
            name: file.name,
          }
        }
        formData.append(&apos;pinataOptions&apos;, JSON.stringify(pinataBody.options));
        formData.append(&apos;pinataMetadata&apos;, JSON.stringify(pinataBody.metadata));
        const url = `${pinataConfig.root}/pinning/pinFileToIPFS`;
        const response = await axios({
          method: &apos;post&apos;,
          url: url,
          data: formData,
          headers: pinataConfig.headers
        })
        console.log(response.data)
        queryPinataFiles();
      } else {
        alert(&apos;select file first&apos;)
      }
    } catch (error) {
      console.log(error)
    }
  }
"><code>  const handleUpload <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (file <span class="hljs-operator">!</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> undefined) {
        const formData <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> FormData();
        console.log(file)
        formData.append(<span class="hljs-string">'file'</span>, file);
        const pinataBody <span class="hljs-operator">=</span> {
          options: {
            cidVersion: <span class="hljs-number">1</span>,
          },
          metadata: {
            name: file.<span class="hljs-built_in">name</span>,
          }
        }
        formData.append(<span class="hljs-string">'pinataOptions'</span>, JSON.stringify(pinataBody.options));
        formData.append(<span class="hljs-string">'pinataMetadata'</span>, JSON.stringify(pinataBody.metadata));
        const url <span class="hljs-operator">=</span> `${pinataConfig.root}<span class="hljs-operator">/</span>pinning<span class="hljs-operator">/</span>pinFileToIPFS`;
        const response <span class="hljs-operator">=</span> await axios({
          method: <span class="hljs-string">'post'</span>,
          url: url,
          data: formData,
          headers: pinataConfig.headers
        })
        console.log(response.data)
        queryPinataFiles();
      } <span class="hljs-keyword">else</span> {
        alert(<span class="hljs-string">'select file first'</span>)
      }
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-function"><span class="hljs-keyword">error</span>)
    }
  }
</span></code></pre><p>You would notice the <code>queryPinataFiles</code> function being called inside, but we haven&apos;t yet defined it. Let us define the function body.</p><pre data-type="codeBlock" text="const queryPinataFiles = async () =&gt; {
    try {
      const url = `${pinataConfig.root}/data/pinList?status=pinned`;
      const response = await axios.get(url, pinataConfig);
      console.log(response.data.rows)
      setPinnedFiles(response.data.rows);
    } catch (error) {
      console.log(error)
    }
  };
"><code>const queryPinataFiles <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">try</span> {
      const url <span class="hljs-operator">=</span> `${pinataConfig.root}<span class="hljs-operator">/</span>data<span class="hljs-operator">/</span>pinList?status<span class="hljs-operator">=</span>pinned`;
      const response <span class="hljs-operator">=</span> await axios.get(url, pinataConfig);
      console.log(response.data.rows)
      setPinnedFiles(response.data.rows);
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-function"><span class="hljs-keyword">error</span>)
    }
  }</span>;
</code></pre><p>Save the file and head over to your app and keep the network tab open.</p><p>Choose any file and press upload to pin it to IPFS. You would see a network call to IPFS being made and once it is successful you would get an IPFS hash in the Response section of the Request. This implies that you have successfully uploaded your file to the network.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/edb935fc1e72436ad10b132ff39de276d37ca91a8f842ac78762e0cada1bdc14.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>One final thing which is remaining is loading the files you uploaded on start of the app. Simple call the <code>queryPinataFiles</code> function in the same <code>useEffect</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7075ce964a79c3de43b9b593c5937f2f98cb4afd605fe54602a7411d0a29c84b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>There are all your files pinned to IPFS. Click on the filename to see the actual details</p><p>VOILA YOU HAVE DONE IT!!!</p><h3 id="h-support" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Support</h3><p>If you liked my article, consider supporting me with a coffee ☕️ or some crypto ( ₿, ⟠, etc)</p><p>Here is my public address <code>0x7935468Da117590bA75d8EfD180cC5594aeC1582</code></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.buymeacoffee.com/atoo">https://www.buymeacoffee.com/atoo</a></p><h3 id="h-lets-connect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Lets connect</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Atoo35">https://github.com/Atoo35</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.linkedin.com/in/atharva-deshpande-187969140/">https://www.linkedin.com/in/atharva-deshpande-187969140/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/atharva_35">https://twitter.com/atharva_35</a></p><h3 id="h-feedback" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Feedback</h3><p>Let me know if I have missed something or provided the wrong info. It helps me keep genuine content and learn.</p>]]></content:encoded>
            <author>atoo@newsletter.paragraph.com (Atoo)</author>
        </item>
        <item>
            <title><![CDATA[Fetching Mirror Posts]]></title>
            <link>https://paragraph.com/@atoo/fetching-mirror-posts</link>
            <guid>ajATNBcgGrNqxsgcfR7U</guid>
            <pubDate>Wed, 30 Nov 2022 22:13:38 GMT</pubDate>
            <description><![CDATA[Hello everyone 👋, I, Atharva Deshpande am back with another article. But this time we move away from discord and into blockchain and Arweave and Mirror. In this article, we would understand how to fetch mirror posts of any Ethereum address by using Arweave&apos;s Graph. This article expects prior knowledge of the fundamentals of blockchain, Arweave and Mirror. Here is the link to Github Repository. You can go ahead and get the code directly but I would recommend reading through the article o...]]></description>
            <content:encoded><![CDATA[<p>Hello everyone 👋, I, Atharva Deshpande am back with another article. But this time we move away from discord and into blockchain and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.arweave.org/">Arweave</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/">Mirror</a>.</p><p>In this article, we would understand how to fetch mirror posts of any Ethereum address by using Arweave&apos;s Graph. This article expects prior knowledge of the fundamentals of blockchain, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.arweave.org/">Arweave</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/">Mirror</a>.</p><p>Here is the link to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Atoo35/fetch-mirror-posts">Github Repository</a>. You can go ahead and get the code directly but I would recommend reading through the article once.</p><h2 id="h-prerequisites" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Prerequisites</strong></h2><ul><li><p>Familiarity with blockchain, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.arweave.org/">Arweave</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/">Mirror</a>.</p></li><li><p>Any code editor. ( I would be using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code.visualstudio.com/download">VSCode</a> )</p></li><li><p>Basic understanding of Javascript</p></li><li><p>Machine with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nodejs.org/en/">NodeJS</a>(v16.15.0) installed.</p></li></ul><h2 id="h-approach" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Approach</strong> 🧠</h2><p>The process of retrieving Mirror posts is split into 2 steps.</p><ul><li><p>Step 1: Retrieve the transactions of a user from the Arweave graph with the tag name <code>MirrorXYZ</code>.</p></li><li><p>Step 2: Query the Arweave API <code>https://arweave.net/&lt;txId&gt;</code> by passing the transaction ID to get the JSON data format.</p></li></ul><h2 id="h-lets-buidl-it" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Let&apos;s BUIDL It</strong> 🛠️</h2><ol><li><p>Create a folder, open it in VSCode and run the command</p></li></ol><pre data-type="codeBlock" text="npm init -y
"><code>npm <span class="hljs-keyword">init</span> -y
</code></pre><pre data-type="codeBlock" text="Edit the `package.json` file so that the scripts tag looks like this.
```json
&quot;scripts&quot;: {
    &quot;start&quot;: &quot;node index.js&quot;
  }
"><code>Edit the `package.json` file so that the scripts tag looks like <span class="hljs-built_in">this</span>.
```json
<span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>
  }
</code></pre><pre data-type="codeBlock" text="
1. Create an `index.js` file and run the command to install Axios which would be used to query the graph and get the JSON file as well.

```js
npm i axios
"><code>
<span class="hljs-number">1.</span> Create an `index.js` file and run the command to install Axios which would be used to query the graph and get the JSON file <span class="hljs-keyword">as</span> well.

```js
npm i axios
</code></pre><pre data-type="codeBlock" text="Your folder structure should look like this

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657790855601/1mYeTV1QS.png align=&quot;left&quot;)
"><code>Your folder structure should look like <span class="hljs-built_in">this</span>

<span class="hljs-operator">!</span>[image.png](https:<span class="hljs-comment">//cdn.hashnode.com/res/hashnode/image/upload/v1657790855601/1mYeTV1QS.png align="left")</span>
</code></pre><ol><li><p>Let&apos;s write the code to query the Arweave graph to get transactions of a user. In the <code>index.js</code> file, copy paste the following code.</p></li></ol><pre data-type="codeBlock" text="const axios = require(&apos;axios&apos;);
arweaveURL = &quot;https://arweave.net&quot;;
const fetchTransactions = async (address) =&gt; {
  try {
    const result = await axios.post(
      `${arweaveURL}/graphql`,
      {
        query: `
                {
                  transactions(
                      tags:[
                        {
                          name:&quot;App-Name&quot;,
                          values:[&quot;MirrorXYZ&quot;],
                        },
                        {
                          name:&quot;Contributor&quot;,
                          values:[&quot;${address}&quot;]
                        }
                      ]
                  sort:HEIGHT_DESC) {
                      edges {
                          node {
                              id
                          }
                      }
                  }
              }
              `
         },
         {
           headers: {
             &apos;Content-Type&apos;: &apos;application/json&apos;
           }
         }
       );
        return result.data.data
      } catch (err) {
        console.log(err);
      }
}
const main = async () =&gt; {
     const response = await fetchTransactions(&quot;0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902&quot;)
     console.log(response.transactions.edges)
}
main()
  .then(() =&gt; process.exit(0))
"><code>const axios <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);
arweaveURL <span class="hljs-operator">=</span> <span class="hljs-string">"https://arweave.net"</span>;
const fetchTransactions <span class="hljs-operator">=</span> async (<span class="hljs-keyword">address</span>) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-keyword">try</span> {
    const result <span class="hljs-operator">=</span> await axios.post(
      `${arweaveURL}<span class="hljs-operator">/</span>graphql`,
      {
        query: `
                {
                  transactions(
                      tags:[
                        {
                          name:<span class="hljs-string">"App-Name"</span>,
                          values:[<span class="hljs-string">"MirrorXYZ"</span>],
                        },
                        {
                          name:<span class="hljs-string">"Contributor"</span>,
                          values:[<span class="hljs-string">"${address}"</span>]
                        }
                      ]
                  sort:HEIGHT_DESC) {
                      edges {
                          node {
                              id
                          }
                      }
                  }
              }
              `
         },
         {
           headers: {
             <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
           }
         }
       );
        <span class="hljs-keyword">return</span> result.data.data
      } <span class="hljs-keyword">catch</span> (err) {
        console.log(err);
      }
}
const main <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
     const response <span class="hljs-operator">=</span> await fetchTransactions(<span class="hljs-string">"0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902"</span>)
     console.log(response.transactions.edges)
}
main()
  .then(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> process.exit(<span class="hljs-number">0</span>))
</code></pre><pre data-type="codeBlock" text="Here, the function `fetchTransactions` simply queries the Arweave Graph using axios. We are sending a graph query that searches for transactions with the tags `App-Name` as `MirrorXYZ` and `Contributor` address as `0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902`.
"><code><span class="hljs-title class_">Here</span>, the <span class="hljs-keyword">function</span> <span class="hljs-string">`fetchTransactions`</span> simply queries the <span class="hljs-title class_">Arweave</span> <span class="hljs-title class_">Graph</span> using axios. <span class="hljs-title class_">We</span> are sending a graph query that searches <span class="hljs-keyword">for</span> transactions <span class="hljs-keyword">with</span> the tags <span class="hljs-string">`App-Name`</span> <span class="hljs-keyword">as</span> <span class="hljs-string">`MirrorXYZ`</span> and <span class="hljs-string">`Contributor`</span> address <span class="hljs-keyword">as</span> <span class="hljs-string">`0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902`</span>.
</code></pre><blockquote><p>Note the above address is of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dev.mirror.xyz/">Mirror Development</a></p></blockquote><pre data-type="codeBlock" text="Run the script by typing the following in your terminal.
```js
"><code>Run the script by typing the following in your terminal.
```js
</code></pre><p>npm start</p><pre data-type="codeBlock" text="    Your terminal should look somewhat like this

    ![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657792467523/PwSpGcCQU.png align=&quot;left&quot;)


3. Let&apos;s write the final function which basically fetches the json data of the post. Add the below function anywhere before the `main` function
```javascript
const fetchArweaveTransactionData = async (transactionId) =&gt; {
      try {
          const response = await axios.get(`https://arweave.net/${transactionId}`)
          return response.data;
      } catch (error) {
          console.log(error)
      }
}
"><code>    Your terminal should look somewhat <span class="hljs-built_in">like</span> this

    ![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657792467523/PwSpGcCQU.png align=<span class="hljs-string">"left"</span>)


<span class="hljs-number">3</span>. <span class="hljs-keyword">Let</span><span class="hljs-comment">'s write the final function which basically fetches the json data of the post. Add the below function anywhere before the `main` function</span>
```javascript
<span class="hljs-keyword">const</span> fetchArweaveTransactionData = <span class="hljs-keyword">async</span> (transactionId) => {
      <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">const</span> response = <span class="hljs-built_in">await</span> axios.<span class="hljs-keyword">get</span>(`https://arweave.net/${transactionId}`)
          <span class="hljs-keyword">return</span> response.data;
      } <span class="hljs-keyword">catch</span> (<span class="hljs-keyword">error</span>) {
          console.log(<span class="hljs-keyword">error</span>)
      }
}
</code></pre><p>We simply pass on the transaction id from the response of the graph API to get the post. update your <code>main</code> function to the following:</p><pre data-type="codeBlock" text="const main = async () =&gt; {
      const response = await fetchTransactions(&quot;0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902&quot;)
      console.log(response.transactions.edges)
      const post = await fetchArweaveTransactionData(response.transactions.edges[0].node.id)
      console.log(post)
}
"><code>const main <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
      const response <span class="hljs-operator">=</span> await fetchTransactions(<span class="hljs-string">"0x9651B2a7Aa9ed9635cE896a1Af1a7d6294d5e902"</span>)
      console.log(response.transactions.edges)
      const post <span class="hljs-operator">=</span> await fetchArweaveTransactionData(response.transactions.edges[<span class="hljs-number">0</span>].node.id)
      console.log(post)
}
</code></pre><pre data-type="codeBlock" text="&gt; Note: For the sake of this article, I am fetching post for only the first transaction from the response.

The response is pretty huge to display it here with the console version but here is the browser version.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657793042082/9eCSaXomb.png align=&quot;left&quot;)
"><code><span class="hljs-operator">></span> Note: For the sake of <span class="hljs-built_in">this</span> article, I am fetching post <span class="hljs-keyword">for</span> only the first transaction <span class="hljs-keyword">from</span> the response.

The response <span class="hljs-keyword">is</span> pretty huge to display it here with the console version but here <span class="hljs-keyword">is</span> the browser version.

![image.png](https:<span class="hljs-comment">//cdn.hashnode.com/res/hashnode/image/upload/v1657793042082/9eCSaXomb.png align="left")</span>
</code></pre><p>That&apos;s it, folks we have successfully retrieved Mirror posts.</p><h3 id="h-support" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Support</h3><p>If you liked my article, consider supporting me with a coffee ☕️ or some crypto ( ₿, ⟠, etc)</p><p>Here is my public address <code>0x7935468Da117590bA75d8EfD180cC5594aeC1582</code></p><h3 id="h-lets-connect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Lets connect</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Atoo35">https://github.com/Atoo35</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.linkedin.com/in/atharva-deshpande-187969140/">https://www.linkedin.com/in/atharva-deshpande-187969140/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/atharva_35">https://twitter.com/atharva_35</a></p><h3 id="h-feedback" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Feedback</h3><p>Let me know if I have missed something or provided the wrong info. It helps me keep genuine content and learn as well.</p>]]></content:encoded>
            <author>atoo@newsletter.paragraph.com (Atoo)</author>
        </item>
    </channel>
</rss>