Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Major API changes #185

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 67 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,19 @@ Want to get started? Check our examples folder. You can check the development st
- [Install](#install)
- [Usage](#usage)
- [API](#api)
- IPLD Resolver
- [Constructor](#ipld-constructor)
- [`.put(node, options, callback)`](#putnode-options-callback)
- [`.get(cid [, path] [, options], callback)`](#getcid--path--options-callback)
- [`.getStream(cid [, path] [, options])`](#getstreamcid--path--options)
- [`.treeStream(cid [, path] [, options])`](#treestreamcid--path--options)
- [`.remove(cid, callback)`](#removecid-callback)
- [`.support.add(multicodec, formatResolver, formatUtil)`](#supportaddmulticodec-formatresolver-formatutil)
- [`.support.rm(multicodec)`](#supportrmmulticodec)
- [Properties](#properties)
- [`defaultOptions`](#defaultoptions)
- [IPLD constructor](#ipld-constructor)
- [`options.blockService`](#optionsblockservice)
- [`options.formats`](#optionsformats)
- [`options.loadFormat(codec)`](#optionsloadformatcodec)
- [`.put(nodes, format, options)`](#putnodes-format-options)
- [`.resolve(cid, path)`](#resolvecid-path)
- [`.get(cids)`](#getcids)
- [`.remove(cids)`](#removecids)
- [`.tree(cid, [path], [options])`](#treecid-path-options)
- [`.addFormat(ipldFormatImplementation)`](#addformatipldformatimplementation)
- [`.removeFormat(codec)`](#removeformatcodec)
- [Properties](#properties)
- [`defaultOptions`](#defaultoptions)
- [Packages](#packages)
- [Contribute](#contribute)
- [License](#license)
Expand Down Expand Up @@ -90,6 +92,8 @@ initIpld('/tmp/ifpsrepo', (err, ipld) => {

## API

The IPLD API works strictly with CIDs and deserialized IPLD Nodes. Interacting with the binary data happens on lower levels. To access the binary data directly, use the [Block API](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md).

### IPLD constructor

> Creates and returns an instance of IPLD.
Expand Down Expand Up @@ -130,83 +134,97 @@ const ipld = new Ipld({
})
```

##### `options.loadFormat(codec, callback)`
##### `options.loadFormat(codec)`

| Type | Default |
|------|---------|
| `Function` | `null` |
| `async Function` | `null` |

Function to dynamically load an [IPLD Format](https://github.com/ipld/interface-ipld-format). It is passed a string `codec`, the multicodec of the IPLD format to load and a callback function to call when the format has been loaded. e.g.
Function to dynamically load an [IPLD Format](https://github.com/ipld/interface-ipld-format). It is passed a `codec`, the multicodec code of the IPLD format to load and returns an IPLD Format implementation. For example:

```js
const multicodec = require('multicodec')
const ipld = new Ipld({
loadFormat (codec, callback) {
if (codec === 'git-raw') {
callback(null, require('ipld-git'))
async loadFormat (codec) {
if (codec === multicodec.GIT_RAW) {
return require('ipld-git')
} else {
callback(new Error('unable to load format ' + codec))
throw new Error('unable to load format ' + multicodec.print[codec])
}
}
})
```

### `.put(node, options, callback)`
### `.put(nodes, format, options)`

> Stores the given IPLD Nodes of a recognized IPLD Format.

- `nodes` (`Iterable<Object>`): deserialized IPLD nodes that should be inserted.
alanshaw marked this conversation as resolved.
Show resolved Hide resolved
- `format` (`multicodec`, required): the multicodec of the format that IPLD Node should be encoded in.
- `options` is applied to any of the `nodes` and is an object with the following properties:
- `hashAlg` (`multicodec`, default: hash algorithm of the given multicodec): the hashing algorithm that is used to calculate the CID.
- `cidVersion` (`number`, default: 1): the CID version to use.
- `onlyHash` (`boolean`, default: false): if true the serialized form of the IPLD Node will not be passed to the underlying block store.

Returns an async iterator with the CIDs of the serialized IPLD Nodes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not return the full block instances? It doesn’t really cost us anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to expose the serialized form of the nodes like that? I don't think it's needed from the IPFS point of view but are there use cases where this is desirable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's needed from the IPFS point of view but are there use cases where this is desirable?

It's actually a good point. When using IPLD you shouldn't really care about how it is serialized. I'm always in favour having a minimal API :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly - it doesn't feel like an application-level concern.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree if the API only returned the final value it had resolved, but it doesn’t, it returns all the CID’s it passed through to resolve the path. It’s already exposing the serialization just by giving you the CID’s of the intermediate nodes and in that case, why not just give me the blocks if you already have them? It costs nothing on the consumer side to ignore the content and just use the CID and it saves a BlockService lookup if you do need the data.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me it's about abstractions. In js-ipld you only care about the the IPLD Data types. A CID is as low as you go, you don't care about how it is serialized, but only about that it got serialized.

IPLD Formats are the low level building block, which is about serialized data. You should use that level if you have needs to operate on that level.

I think not exposing the serialized data would make IPLD easier to use as it is one less concept to learn.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikeal This discussion is the last outstanding one. Would you be OK with moving forward with the current state?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya, it’s fine, go ahead and merge.



### `.resolve(cid, path)`

> Retrieves IPLD Nodes along the `path` that is rooted at `cid`.

> Store the given node of a recognized IPLD Format.
- `cid` (`CID`, required): the CID the resolving starts.
- `path` (`IPLD Path`, required): the path that should be resolved.
alanshaw marked this conversation as resolved.
Show resolved Hide resolved

`options` is an object that must contain one of the following combinations:
- `cid` - the CID of the node
- `[hashAlg]`, `[version]` and `format` - the hashAlg, version and the format that should be used to create the CID of the node. The
`hashAlg` and `version` defaults to the default values for the `format`.
Returns an async iterator of all the IPLD Nodes that were traversed during the path resolving. Every element is an object with these fields:
- `remainderPath` (`string`): the part of the path that wasn’t resolved yet.
- `value` (`*`): the value where the resolved path points to. If further traversing is possible, then the value is a CID object linking to another IPLD Node. If it was possible to fully resolve the path, `value` is the value the `path` points to. So if you need the CID of the IPLD Node you’re currently at, just take the `value` of the previously returned IPLD Node.
mikeal marked this conversation as resolved.
Show resolved Hide resolved

It may contain any of the following:

- `onlyHash` - If true the serialized form of the node will not be passed to the underlying block store but the passed callback will be invoked as if it had been
### `.get(cids)`

`callback` is a function that should have the signature as following: `function (err, cid) {}`, where `err` is an Error object in case of error and `cid` is the cid of the stored object.
> Retrieve several IPLD Nodes at once.

### `.get(cid [, path] [, options], callback)`
- `cids` (`Iterable<CID>`): the CIDs of the IPLD Nodes that should be retrieved.

> Retrieve a node by the given `cid` or `cid + path`
Returns an async iterator with the IPLD Nodes that correspond to the given `cids`.

`options` is an optional object containing:
Throws an error if a IPLD Node can’t be retrieved.

- `localResolve: bool` - if true, get will only attempt to resolve the path locally
### `.remove(cids)`

`callback` should be a function with the signature `function (err, result)`, the result being an object with:
> Remove IPLD Nodes by the given `cids`

- `value` - the value that resulted from the get
- `remainderPath` - If it didn't manage to successfully resolve the whole path through or if simply the `localResolve` option was passed.
- `cid` - Where the graph traversal finished - if `remainderPath` has a value, this will be where it has its root
- `cids` (`Iterable<CID>`): the CIDs of the IPLD Nodes that should be removed.

### `.getMany(cids, callback)`
Throws an error if any of the Blocks can’t be removed. This operation is not atomic, some Blocks might have already been removed.

> Retrieve several nodes at once

`callback` should be a function with the signature `function (err, result)`, the result is an array with the nodes corresponding to the CIDs.
### `.tree(cid, [path], [options])`

> Returns all the paths that can be resolved into.

### `.getStream(cid [, path] [, options])`
- `cid` (`CID`, required): the CID to get the paths from.
- `path` (`IPLD Path`, default: ''): the path to start to retrieve the other paths from.
- `options`:
- `recursive` (`bool`, default: false): whether to get the paths recursively or not. `false` resolves only the paths of the given CID.

> Same as get, but returns a source pull-stream that is used to pass the fetched node.
Returns an async iterator of all the paths (as Strings) you could resolve into.

### `.treeStream(cid [, path] [, options])`

> Returns all the paths under a cid + path through a pull-stream. Accepts the following options:
### `.addFormat(ipldFormatImplementation)`

- `recursive` - bool - traverse through links to complete the graph.
> Add support for an IPLD Format

### `.remove(cid, callback)`
- `ipldFormatImplementation` (`IPLD Format`, required): the implementation of an IPLD Format.

> Remove a node by the given `cid`

### `.support.add(multicodec, formatResolver, formatUtil)`
### `.removeFormat(codec)`

> Add support to another IPLD Format
> Remove support for an IPLD Format

### `.support.rm(multicodec)`
- `codec` (`multicodec`, required): the codec of the IPLD Format to remove.

> Removes support of an IPLD Format

### Properties

Expand Down