The IPFS API
Background
When you run your IPFS node as a daemon, an HTTP RPC API is automatically exposed. Because every CLI command is available on the API, you can use this API to programmatically operate as if you were using the IPFS CLI. Note that the IPFS API is not a REST API; all endpoints are accessible by using the HTTP POST method.
You can access the IPFS API endpoint for your local node at http://localhost:5001/api/v0/<operation>
. Note that the 5001
port is used by default when you spin up your node.
Although accessing the API directly through HTTP requests is a valid approach, there are tools available for the two main programming languages of the IPFS ecosystem: Go (Golang) and JavaScript.
The main implementation of IPFS is kubo(formerly go-ipfs), which allows you to set up your node by spinning up a daemon application written in Go. JS-IPFS is an officially supported implementation of IPFS in JavaScript. You can take three approaches to use these implementations in your application.
- Embedded node: if you want your application to spin up an IPFS node, then use
Go-IPFS
orJS-IPFS
. - Client: if you already have a running IPFS node, then you can use a client written in Go or JS to communicate with the node. Use go-ipfs-api for Go, and js-ipfs-http-client for JS.
- HTTP API: send HTTP requests directly from your Go or JS application through a HTTP gateway to interact with the node.
Both JS-IPFS
and js-ipfs-http-client
work in the browser with some considerations noted in their READMEs.
Connecting to an IPFS node by using the Go client
In this exercise, you will use the Go client to interact with a running IPFS node.
By the end of the exercise, you should be able to:
- Connect to a running IPFS node.
- Add a file.
- Print the content of the file.
- Download the file to your computer.
- Add the file to IPNS.
Video: IPFS API Tutorial
Prerequisites
- You must have Go installed. In this exercise, version 1.18 is used. If you do not have Go installed, refer to this page. If you want to install multiple versions of Go, refer to this page.
- Clone the
https://github.com/protocol/launchpad-tutorials
Git repository, which contains all the sample applications used in the Launchpad program. - You must have an IPFS node running at the default
5001
port. Watch this video to learn how to spin up an IPFS node.
Instructions
In an editor, open the
ipfs-go-client
folder of thelaunchpad-tutorials
repository.Examine the
go.mod
file, which contains the dependencies of the application. Note that thegithub.com/ipfs/go-ipfs-api
is set as a dependency, and the rest of dependencies are indirect. To read more about indirect dependencies in Go, refer to this page.Open the
app/main.go
file, which contains the code for this exercise. Notice that there are several not implemented methods, which you will complete throughout the exercise.
Review the “main” Function
Review the
func main()
(on ~ line 39), which is the entry point of the application. This function calls the different functions that you will implement and handles their result for you.A connection to the node is created by providing the location of the node’s API (the default port 5001).
sh := shell.NewShell("localhost:5001")
The NewShell
method returns a *shell.Shell
object that exposes all the available methods to interact with the IPFS node.
Add a File Using the IPFS API
- Go back up to ~ line 15, and add a file that contains the
Hello from Launchpad!
text to IPFS in theaddFile
function:
func addFile(sh *shell.Shell, text string) (string, error) {
return sh.Add(strings.NewReader(text))
}
The Add
method expects a reader, which can be generated from reading a local file or providing a string.
If no errors have occurred, the CID of the added file is returned.
Read a File Using the IPFS API
- Next, you will read the content of the file by using the
Cat
method. Add in the following to thereadFile
function (on ~ line 19):
func readFile(sh *shell.Shell, cid string) (*string, error) {
reader, err := sh.Cat(fmt.Sprintf("/ipfs/%s", cid))
if err != nil {
return nil, fmt.Errorf("Error reading the file: %s", err.Error())
}
bytes, err := io.ReadAll(reader)
if err != nil {
return nil, fmt.Errorf("Error reading bytes: %s", err.Error())
}
text := string(bytes)
return &text, nil
}
The readFile()
function retrieves data and puts it in a buffer, converts it into a byte array, then converts that byte array into a string.
An IPFS canonical path is passed to the Cat
method. The Cat
method returns a reader, so the io.ReadAll
helper function is used to get the bytes of the file. Then, the bytes are cast into a string.
Download a File Using the IPFS API
- In the next function,
downloadFile
, you will download the file to your computer by using the Get method from the Shell struct. Thefunc downloadFile
returns a file using the CID:
func downloadFile(sh *shell.Shell, cid string) error {
return sh.Get(cid, YourLocalPath)
}
The Get
method expects two parameters: the CID of the file and the local path of your computer where the file will be downloaded.
YourLocalPath = "~/Path/to/Directory"
is a constant defined at the beginning of the main.go
file, where you should add the path on your local machine that you want the files downloaded to (at ~ line 13).
Publish a File to IPNS Using the IPFS API
To publish your file to IPNS you will need a public/private key pair, which is used as a pointer to a CID. You can read more about IPNS in the documentation.
By default, when you install a local IPFS node, a public/private key pair called self
is created.
- In a new terminal window, list your IPFS keys.
> ipfs key list -l
<YOUR_PUBLIC_KEY> self
If you have not created any other key pair, only the self
keypair should be listed.
Copy the public key, which starts with k...
, as you will need it to publish the file to IPNS.
- The
main.go
file defines aYourPublicKey
constant at the beginning. Include your public key in the constant.
const YourPublicKey = "k..."
- Publish the file to IPNS by using the
PublishWithDetails
method in theaddToIPNS
function that is there already:
func addToIPNS(sh *shell.Shell, cid string) error {
var lifetime time.Duration = 50 * time.Hour
var ttl time.Duration = 0 * time.Microsecond
_, err := sh.PublishWithDetails(cid, YourPublicKey, lifetime, ttl, true)
return err
}
The PublishWithDetails
method expects several parameters:
cid
: the CID of the file that will be published to IPNS.key
: the public key that will be used to publish the file. In the previous snippet, the public key constant is provided.lifetime
: the time that the IPNS record will be valid. Basically, how long IPNS will keep the mapping relationshippublic key --> CID
. By default, 24 hours.ttl
: how long IPNS will cache the record.resolve
: check if the given path can be resolved before publishing. By default,true
.
In the previous snippet, the record is kept in IPNS for 50 hours and there is no cache since the ttl
variable is at 1 microsecond.
Retrieve an IPNS Record Using the IPFS API
- Use your public key to query IPNS in the
resolveIPNS
function that is there. The result will be the CID of the file that you published.
func resolveIPNS(sh *shell.Shell) (string, error) {
return sh.Resolve(YourPublicKey)
}
Run your Program
Verify that everything works together by running the Go application.
- Change directory with
cd
into theipfs-go-client/app
directory - Make sure you have ipfs running (
ipfs daemon
in a separate terminal window) then:
> go run .
You should see output like:
Adding file to IPFS
File added with CID: QmNsA8eUBSbpdCVHMLa8Py5TcNoZ1D9U5GkginqktrqNF1
...output omitted...
IPNS is pointing to: /ipfs/QmNsA8eUBSbpdCVHMLa8Py5TcNoZ1D9U5GkginqktrqNF1
You can see an example of the completed code here