IPFS Dedicated Gateway

Hello, I have been having difficulties with getting my dedicated gateway to work since the public gateway was deprecated back in August. This is a new project that never used the public gateway in the first place. I have tried googling the errors but end up confused because I am fairly new at next.js, ipfs, gateways, etc. I would appreciate any help/tips that anyone might have.

The errors that I get in my create-nft.js file is the following:

rror uploading the file: HTTPError create-nft.js?8222:58
at Object.errorHandler [as handleError] (core.js?f126:75:1)
at async Client.fetch (http.js?8f3e:149:1)
at async addAll (add-all.js?ae3c:16:1)
at async last (index.js?7e49:13:1)
at async Object.add (add.js?ff8f:9:1)
fetch.browser.js?c17b:94

and

POST https://https:5001/api/v0/add?stream-channels=true&progress=false net::ERR_NAME_NOT_RESOLVED

type or paste code here

Hi @Rodri09, welcome to our forums!

I think the last error is straightforward - the URL is missing the hostname. It should be something like:
https://https://dedicated_gw.infura-ipps.io:5001/api/v0/add?stream-channels=true&progress=false

The first error may be related?

I hope this helps you solve your issue, Iā€™d be grateful if you can let us know the outcome. Come back with any other questions you have.

Warm regards,
Chris | Infura | ConsenSys

Hello @chris.paterson, thank you very much for responding. I thought that I did have my dedicated_gw in my code. Might it have something to do with what I have as host below for my const client? I have my dedicated gateway name as const url for my async functions instead. Am I not formatting it correctly?

const ipfsClient = require('ipfs-http-client');
const projectId = '';
const projectSecret = process.env.REACT_APP_SECRET_KEY;

const auth =
'Basic' + Buffer.from(projectId + ':' + projectSecret).toString('base64');

const client = ipfsClient.create({
    host: 'https://ipfs.infura.io:5001/api/v0',
    port: 5001,
    protocol: 'https',
    headers: {
        authorization: auth,
    },
});
export default function CreateItem() {
    const [fileUrl, setFileUrl] = useState(null);//allow ipfs file to upload
    const [formInput, updateFormInput] = useState({price: '', name: '', description: ''});
    const router = useRouter();//reference to router

    //monitor unchanged events
    async function onChange(e) {
        const file = e.target.files[0]//event to envoke
        try{ //try uploading the file
            const added = await client.add(//add item source file
                file,//pass in file
                {
                    progress: (prog) => console.log(`received: ${prog}`)
                }
            )
            //where file saved to
            const url = `https://vivi-nftproject.infura-ipfs.io/ipfs`
            setFileUrl(url)//to save it
        }catch(e){
            console.log('Error uploading the file: ', e)
        }
    }
    //1.function to create item and upload to ipfs
    async function createItem(){
        const {name, description, price} = formInput; //value from the form input
        
        //form validation
        //if no name, description, price, or fileurl, then return const data report
        if(!name || !description || !price || !fileUrl) {
            return
        }

        const data = JSON.stringify({
            name, description, image: fileUrl
        });

        try{
            const added = await client.add(data)
            const url = `https://vivi-nftproject.infura-ipfs.io/ipfs`
            //pass the url to save it on Polygon after IPFS upload
            createNFTSale(url)
        }catch(error){//catch possible errors
            console.log(`Error uploading file: `, error)
        }
    }

Could you try adding the following to every instance when you create the url:

${added.path}

So you will have this:

const url = ` https://vivi-nftproject.infura-ipfs.io/ipfs/${added.path}

Sorry, auto-formatting wonā€™t let me add backtick ` at the end of the const url , but you got it :grin:!

Hello @lovekosmas, thank you for chiming in. With ${added.path}, there wasnā€™t a change in the error. I still get the same one. I deleted the artifacts file and ran npx hardhat compile again just in case but it was still the same.

Hi @Rodri09,

I think your problem might stem from your line:

host: 'https://ipfs.infura.io:5001/api/v0',

You probably meant to use ā€œurl:ā€ instead of ā€œhost:ā€, or just replace the line with:

host: 'ipfs.infura.io'

Let us know if this helps.

Warm regards,
Chris | Infura | ConsenSys

The docs here:
https://www.npmjs.com/package/ipfs-http-client#createoptions
is the go to place to check your syntax. There are lotā€™s of options as to how your can specify whatā€™s needed.

Thereā€™s also an ipfs-http-client example https://docs.infura.io/infura/networks/ipfs/how-to/make-requests

1 Like

By the way, sorry I miss-spoke in my initial response, I shouldnā€™t have said ā€œdedicated_gwā€ as an IPFS gateway is a quick and easy way to retrieve an IPFS object, i.e. like this:

https://chris.infura-ipfs.io/ipfs/Qmaq9QhJxaCypTQUaM7vxJUAvpUsDEpcWTKZZuhR6WyQNX

or using the public gateway provided by the IPFS organisation:

https://ipfs.io/ipfs/Qmaq9QhJxaCypTQUaM7vxJUAvpUsDEpcWTKZZuhR6WyQNX

whereas your error is referring to the Infura/IPFS API endpoint. Sorry I was confused there.

Hello @chris.paterson, I was wondering if this IPFS path is the standard in the gateway?

It has shown up often and wanted to know if I skipped a step after creating the IPFS project.

I followed your suggestions to look at https://www.npmjs.com/package/ipfs-http-client#createoptions for the url/host
and
Make requests | INFURA
Under the Infura docs, I formatted it to how one would if using the official ipfs-http-client library, which I do have downloaded. Also the code is not in my index.js file since it serves as my homepage and rather I have it in a file named create-nfts.js since that is my upload nfts page with the upload name, description, button, etc. Might that play a factor? I noticed that Infura docs said to have it in the index.js file but I am creating an NFT Marketplace instead so formatting wise, it doesnā€™t make sense to have there.

const ipfsClient = require('ipfs-http-client');
const projectId = '2GxDqcI0uoDOqJJaCbPCUTcM9AZ';
const projectSecret = process.env.REACT_APP_SECRET_KEY;


const auth =
'Basic' + Buffer.from(projectId + ':' + projectSecret).toString('base64');

const client = ipfsClient.create({
    host: 'ipfs.infura.io',
    port: 5001,
    protocol: 'https',
    headers: {
        authorization: auth,
    },
});
client.pin.add('QmeGAVddnBSnKc1DLE7DLV9uuTqo5F7QbaveTjr45JUdQn').then((res) => {
    console.log(res);
});

Yet, I now have these two errors about authorization, which is why I ask the above questions:

POST https://ipfs.infura.io:5001/api/v0/pin/add?recursive=true&stream=true&arg=QmeGAVddnBSnKc1DLE7DLV9uuTqo5F7QbaveTjr45JUdQn 401 (Unauthorized)

and
Uncaught (in promise) HTTPError: basic auth header is invalid

at Object.errorHandler [as handleError] (core.js?f126:75:1)
at async Client.fetch (http.js?8f3e:149:1)
at async addAll (add-all.js?95ce:8:1)
at async last (index.js?7e49:13:1)

Hi @Rodri09,

well done on fixing the create options - they look good.

Your 401 error could be because of the missing space on the end of ā€œBasicā€. The resulting header needs too look like the one documented here:
Authenticate requests | INFURA
The space separating ā€œBasicā€ and ā€œthe tokenā€ is essential.

is just a CID for some random file Iā€™ve uploaded. IPFS uses a hash of the content of the file as the ā€œkeyā€ or the ā€œnameā€ for interacting with it. Rather than a filename - if you see what I mean? @lovekosmas alluded to this in their reply earlier.

Note this line pins an already uploaded IPFS object (it adds a pin). If you want to upload a file, then itā€™s documented here:
js-ipfs/docs/core-api/FILES.md at master Ā· ipfs/js-ipfs Ā· GitHub
There are a frightening variety of options for this simple call but something like:

 client.add(filename).then((res) => {
   console.log(res);
});

will print out a result object, part of which is the CID that was calculated from the content. Use that CID to access the file later with a gateway.

Thereā€™s a lot to know about JavaScript, IPFS, etc, to get started in this space.

Warm regards,
Chris | Infura | ConsenSys

Hi @chris.paterson , thank you for your feedback.

I donā€™t quite understand what you mean about a missing space on the end of ā€œBasicā€ because I see a space on the end of it. const auth = 'Basic' + Buffer.from(projectId + ':' + projectSecret).toString('base64');

Also for Authorization HTTP header, I would need to add
Authorization: Basic <base64(USERNAME:PASSWORD)> but where would I add that? I thought I was already granting authorization in my previous code of

const auth = 'Basic' + Buffer.from(projectId + ':' + projectSecret).toString('base64');

const client = ipfsClient.create({
    host: 'ipfs.infura.io',
    port: 5001,
    protocol: 'https',
    headers: {
        authorization: auth,
    },
});

Or does that have to do with index.js (homepage) instead?

About the CID, I think I will use the upload within the Infura UI. Is there a limit of how many

client.pin.add('QmXQVD875CkTjNoziNfY68G3iz6EbNpmU9eBRC91XDaxaA').then((res) => { console.log(res); });

instances that I can have in a js file?

If you change

TO:

Then the the 401 will be fixed. You see the space after the Basic?

Once you get past that then, with a lot of hard work and learning, you will be able to progress. Itā€™s quite a journey, learning to be a software developer, I wish you luck. Itā€™ll be fun :slight_smile: .

@chris.paterson
Hello, after I added the space in 'Basic ā€™ like how you mentioned it above, I got a the same 401 unauthorized error as before and

Uncaught (in promise) HTTPError: basic auth failure: invalid project id or project secret

Now I have an invalid project id or project secret. I searched that something similar to this happened before and followed the advice to use ā€˜dotenvā€™ from Please help with 'Invalid project id' - #55 by SaifulJnU
and came up with the following code. I also created another IPFS project to use a different project id and project secret. I have a new dedicated gateway name as well.
I now have it showing:

error - ./node_modules/dotenv/lib/main.js:1:0

Module not found: Canā€™t resolve ā€˜fsā€™

Import trace for requested module:

./pages/create-nft.js

https://nextjs.org/docs/messages/module-not-foun

require('dotenv').config()
console.log(process.env)

const ipfsClient = require('ipfs-http-client');
const projectId = '2HvMYj05gO22Mz5aWh7B8dsizbx';
const projectSecret = process.env.REACT_APP_SECRET_KEY;

const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64');

const client = ipfsClient.create({
    host: 'ipfs.infura.io',
    port: 5001,
    protocol: 'https',
    headers: {
        authorization: auth,
    },
});
client.pin.add('QmXQVD875CkTjNoziNfY68G3iz6EbNpmU9eBRC91XDaxaA').then((res) => {
    console.log(res);
});
export default function CreateItem() {
    const [fileUrl, setFileUrl] = useState(null);//allow ipfs file to upload
    const [formInput, updateFormInput] = useState({price: '', name: '', description: ''});
    const router = useRouter();//reference to router

    //monitor unchanged events
    async function onChange(e) {
        const file = e.target.files[0]//event to envoke
        try{ //try uploading the file
            const added = await client.add(//add item source file
                file,//pass in file
                {
                    progress: (prog) => console.log(`received: ${prog}`)
                }
            )
            //where file saved to
            const url = `https://vivi-project.infura-ipfs.io/ipfs/${added.path}`
            setFileUrl(url)//to save it
        }catch(e){
            console.log('Error uploading the file: ', e)
        }
    }
    //1.function to create item and upload to ipfs
    async function createItem(){
        const {name, description, price} = formInput; //value from the form input
        
        //form validation
        //if no name, description, price, or fileurl, then return const data report
        if(!name || !description || !price || !fileUrl) {
            return
        }

        const data = JSON.stringify({
            name, description, image: fileUrl
        });

        try{
            const added = await client.add(data)
            const url = `https://vivi-project.infura-ipfs.io/ipfs/${added.path}`
            //pass the url to save it on Polygon after IPFS upload
            createNFTSale(url)
        }catch(error){//catch possible errors
            console.log(`Error uploading file: `, error)
        }
    }
    //2.Listing item to sell
    async function createNFTSale(url){
        const web3Modal = new Web3Modal();//connect to user wallet
        const connection = await web3Modal.connect();
        const provider = new ethers.providers.Web3Provider(connection);

        //signing the transaction
        const signer = provider.getSigner();
        //interact with nft contract
        let contract = new ethers.Contract(nftaddress, NFT.abi, signer);
        let transaction = await contract.createToken(url);
        let tx = await transaction.wait()

        /*get the tokenId from above transaction,
        events array is returned, the first item from that event
        is the event*/
        console.log('Transaction: ',tx)
        console.log('Transaction events: ',tx.events[0])
        let event = tx.events[0]//reference to that array
        let value = event.args[2]//third value token id
        let tokenId = value.toNumber() //convert value to number

        //reference to the price entered in the form
        const price = ethers.utils.parseUnits(formInput.price, 'ether')

        //connected to nftmarket contract
        contract = new ethers.Contract(nftmarketaddress, Market.abi, signer);

        //get listing price
        let listingPrice = await contract.getListingPrice()
        listingPrice = listingPrice.toString()//to send value to contract

        //contract to create market item
        transaction = await contract.createMarketItem(
            nftaddress, tokenId, price, { value: listingPrice }
        )

        await transaction.wait()

        //redirect user to home
        router.push('/')

    }

Hi @Rodri09 , progress! You saw the error change, so now ask your self why might the project ID or secret be invalid? Suggest you put a console.log() where you are getting the secret from the environment to double check that itā€™s working. What is the value of projectSecret?

Note that using dotenv in a react app is very difficult as I understand it. But that question would be best directed by a react forum, these are not really Infura/crypto questions.

@chris.paterson
Thank you for all your help. Iā€™ll go ahead and reach out to a React forum and search there as well. If I have any further Infura-related questions, Iā€™ll start another question on this forum. Thanks again.

1 Like