How to fetch content from IPFS with jsipfs?

I have an issue with the Documentation of jsipfs for:

ipfs.cat
ipfs.get

I just want to fetch the content of a binary file into a single Uint8Array.
And I do not know how to do this.

const validCID = '<CID>'

ipfs.files.get(validCID, function(err, files) {
    files.forEach((file) => {
        console.log(file.path)
        console.log("File content >> ", file.content.toString('utf8'))
    })
})

First hit on google: Getting file from hash in js-ipfs - Stack Overflow
Was it that difficult to search first?

Note that in the snippit it does file.content.toString('utf8'), you’re probably looking for file.content (so without the toString('utf8').

That function: ipfs.files.get does not appear to exist in the Documentation File:
FILES.md

And in my jsipfs ipfs.files.get does not exist.

Try the read method instead.
I don’t know why .get is gone (or renamed?).

And the only equivalent I found was ipfs.files.read refers to uint8ArrayConcat.
I don’t know what that is or how to implement it.

From: js-ipfs/read.js at master · ipfs/js-ipfs · GitHub

  /**
   * Read a file
   *
   * @param {string | CID} path - An MFS path, IPFS Path or CID to read
   * @param {ReadOptions & AbortOptions} [options]
   * @returns {AsyncIterable<Uint8Array>}
   * @example
   * ```js
   * const chunks = []
   *
   * for await (const chunk of ipfs.files.read('/hello-world')) {
   *   chunks.push(chunk)
   * }
   *
   * console.log(uint8ArrayConcat(chunks).toString())
   * // Hello, World!
   * ```
   */

Read carefully. This part:

   * for await (const chunk of ipfs.files.read('/hello-world')) {
   *   chunks.push(chunk)
   * }

Seems to be iterating over the Uint8Array chunks. (it gets the chunks from the network and stores them locally in chunks.

the uint8ArrayConcat is a way of concatenating chunks which gives you back one big Uint8Array.
See the uint8arrays package for details, that’s what’s being used here.

I just found this by reading the code and following what it does…

1 Like

Is there any better function or shouldn’t there be one?

I mean, what applications are there, that need to work on the chunks, instead of the files in their entirety?

This is the js-ipfs library. It’s low level.
It’s should be the js version comparable to the go version. The API’s should be comparable.

I think what you get is perfectly fine.
If you need it to be represented differently then make your helper functions on top of it. And if you think it’s useful for a wide audience, make a library out of it for others to use.

Is there a reason why you can’t use this as-is?

You can also use ipfs.cat which has a nice example in this (quite big) examples file:

const data = uint8ArrayConcat(await all(ipfs.cat(cid)))

Provided you have it-all, if not you need to add it:

const all = require('it-all')
const data = uint8ArrayConcat(await all(ipfs.cat(cid)))

A one-liner… What more do you want?

1 Like

This is beautiful, thanks for the help @markg85 . I apologize for re-activating this very old thread, but I am having a related issue.

I am building an app where we are viewing NFT’s. Some of them address the content directly and provide us with URL’s like "ipfs://Qmd56wTFasSyMpaaSZVp2kLKzK8GeDPJMEMz4rPppnzznF" to fetch the file directly from.

Some of them, on the other hand, we are given URL’s that look like "ipfs://QmQ44dZ1pAw5T8kftZ6A28dLv2QoAhu9CXMxvK2MQa8exs/1648.png" where we are given the hash of the directory, and then the actual name and extension of the file in that directory.

I can obviously use the get method to iterate through the directory and then chunk up each file, but this requires that I download the whole directory and, to the best of my knowledge, there is no way to access the file name to filter through this API.

Is there some easy way to address an individual file from a directory where we know the hash of the directory, and also the name of the file that I am unaware of?

Thank you!

Hello jackc,
Good question, I also would like to know how to be sure not to have to download the whole directory/merkle-tree when you only need one file out of it. I was thinking maybe with ipfs.object.stat it is possible to get the hash of the file itself (without the tree containing it), and then get to it with that hash.
Looking forward to hear your thoughts about this.

@RenaPero we ended up taking the easiest way out and just setting up a gateway with https://www.pinata.cloud/

I think that the LS command could work to get a list of file names and hashes, but Infura does not yet have this endpoint enabled on their IPFS nodes for some reason. The other option would be running your own node and connecting with js-ipfs to do this!

So, to help others out for this initial question. Downloading a file from IPFS in js.

I’m only posting this because i found a need for it myself and actually ended up in this topic reading my own replies :slight_smile: Apparently the JS side changed a bit since then so here’s an updated answer on how to get your file.

// Just a handy tool
const all = require('it-all')

// You want this. Else you're stuck in merging uint8arrays.
const uint8ArrayConcat = require('uint8arrays').concat

// Obviously :)
const ipfsapi = require('ipfs-http-client')

// Connect to your node that has port 5001 exposed.
const client = ipfsapi.create('http://127.0.0.1:5001/api/v0')

// Get the data in one large uint8array
// Change "cid" to your cid. Can be a string.
const data = uint8ArrayConcat(await all(client.cat(cid)))

// Convert your data to what makes sense in your case. In my case it was text to i needed this
const decodedData = new TextDecoder().decode(data).toString();

That’s it, now you have your data.