Skip to content

RFC: separate API for adding multiple? #10

Open
@alanshaw

Description

@alanshaw

Here in IPFSX adding content always returns an iterator, which is a nice consistent API, but when adding a single file calling .first() or .last() on the iterator feels a little clunky and it seems to me that the more usual case is actually adding a single file, so I'd like to keep that API as simple and clean as possible.

I've ruled out:

  • Automatically changing the return type to be a Promise if we detect a single item is being added and an Iterable otherwise. This is too weird, and I think people would get confused.
  • Always return a Promise that is monkey patched to also be Iterable 😱. This makes me feel weird, and it's not obvious what the promise would resolve to when adding multiple and I think people will accidentially await when they should be iterating i.e. its also confusing
  • Always return a Promise that resolves to an Iterable if adding multiple - similar confusion ranking 😂. There's also no need to force execution onto the next tick if we're going to resolve immediately to an async iterable.

So, what if this instead:

ipfs.add (single, returns a Promise) & ipfs.addEach (multiple, returns an async iterator)

  • ipfs.add accepts a Buffer or Iterable that yields buffers and returns a Promise that resolves to a CID
    e.g.
    const cid = await ipfs.add(Buffer.from('hello world'))
    // or
    const cid = await ipfs.add(fs.createReadStream('/path/to/file'))
  • ipfs.addEach accepts an iterable (optionally async) where each yielded item is a file to be added. Each item can be a Buffer or Iterable that yields buffers or a { path, content } object. It returns an async iterable of { cid, path }
    e.g.
    const adder = ipfs.addEach([
      { path: 'root/file1', content: fs.createReadStream(/*...*/) },
      { path: 'root/file2', content: fs.createReadStream(/*...*/) }
    ])
    
    for await (const { cid, path } of adder)
      // ...

...and pushing this out to other API methods that write DAG nodes:

  • ipfs.block.put & ipfs.block.putEach
  • ipfs.dag.put & ipfs.dag.putEach
  • etc.

I want to keep the API surface area as small as possible so this is a step away from that. In general I believe that functions should be permissive in what they accept and consistent in what they return. However, we're not really talking about that here, what we're talking about is splitting on difference in operation - ipfs.add behaves very differently when you're adding multiple files than it does when adding a single file and combining the two together makes it very difficult to return a consistent value with a "nice" API for both cases.

Interested to hear opinions and alternatives and settle on the most convenient and best API. Adding stuff programmatically to IPFS needs to be way easier. I think what we have here in IPFSX is a good start but I'd like to make it even better!

cc @olizilla @lidel @hacdias @achingbrain @hugomrdias @daviddias @jacobheun @vasco-santos @mikeal @vmx @Gozala (plz mention others if I've missed anyone that might be interested...)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions