algod REST API Example

See Using the REST APIs for an overview on how Algorand's APIs are available using REST servers.

The REST API for the algod process provides calls to check the network status (/v1/status) and to retrieve a specific block (/v1/block/{round}). This tutorial walks through using the REST API from a sample GO application. In this example, we use the status call to get the last round processed by the blockchain and retrieve that blocks metadata. This example makes use of the go-swagger project to produce a REST client for the specific algod swagger.json file. There are many ways to install go-swagger. In this example, we just install it from the source using the following command:

go get -u github.com/go-swagger/go-swagger/cmd/swagger

Create your go project in your desired folder. In this example we created a project called swagger-example and created a main.go. Before putting any code in the main file, the REST client needs to be generated. Additionally, we need the swagger.json file that currently resides in the data directory for algod (future releases will put it in the bin directory).

cp ~/node/data/swagger.json .

The /swagger.json REST endpoint will also provide this file:

curl http://$(cat ~/node/data/algod.net)/swagger.json > swagger.json

The client can be generated using the following command, once go-swagger is installed.

swagger generate client -f swagger.json

This will generate client and models packages for using the REST API. These can be imported into your sample application.

Remember to update the algorand/swagger-example path to reflect your project's location.


package main

import (
	"encoding/json"
	"fmt"
	"log"

	httptransport "github.com/go-openapi/runtime/client"

	"github.com/algorand/swagger-example/client"
	"github.com/algorand/swagger-example/client/operations"
)

The main configuration parameters that will be required to use the REST API are the servers listening address and port, and the specific API token that is needed to make REST calls. These can be retrieved from the data directory in the algod.net and algod.token files. The following code just sets up the configuration 


const (
	ServerAddress           = "localhost:8080"
	TokenRequestKey         = "X-Algo-API-Token"
	TokenRequestKeyLocation = "header"
)

// This code requires a swagger generated client. To generate a client:
//     `go get -u github.com/go-swagger/go-swagger/cmd/swagger`
//     `swagger generate client -f ./swagger.json`
func main() {

	cfg := client.DefaultTransportConfig().WithHost(ServerAddress)
	apiclient := client.NewHTTPClientWithConfig(nil, cfg)

	// You will need to add your own logic for fetching a token
	token := "24dcaa3f1c75652354a61bab18f399a06d386d3b63d1f9f3d0d5d37221bbb1df"
	apiKeyQueryAuth := httptransport.APIKeyAuth(TokenRequestKey, TokenRequestKeyLocation, token)

Next, we need to make a call to GetStatus. Before doing this we first need to set up any parameters. In this example, there are none required. The parameters object and the API key are passed to the GetStatus function.



	// Example: get node /status
	sParams := operations.NewGetStatusParams() // the defaults are fine
	statusResponse, err := apiclient.Operations.GetStatus(sParams, apiKeyQueryAuth)
	if err != nil {
		log.Fatal(err)
	}

The GetStatus reponse will contain a NodeStatus object pointer in the payload field. We can use this to get and print out the last round processed by the blockchain.

 
	// unwrap the status and print the last round
	nodeStatus := statusResponse.Payload
	if nodeStatus == nil {
		log.Fatal(fmt.Errorf("AlgoD API returned empty status response"))
	}
	if nodeStatus.LastRound == nil {
		log.Fatal(fmt.Errorf("AlgoD API returned malformed status response"))
	}
	lastRound := *nodeStatus.LastRound
	fmt.Printf("Last Round:\t%d\n", lastRound)

The lastRound can now be used as a parameter for the GetBlock function. This will require seting up the parameters similar to the previous call and passing the API token to the call. The response's payload will also contin a Block object pointer will all the block metadata, which then can be printed.


	// Example: dump the last block we've heard to stdout.
	// This will only succeed if the server is running in archival mode, and is keeping old blocks.
	bParams := operations.NewGetBlockParams()
	// cast the round number to int64. go-swagger doesn't handle unsigned types.
	bParams.SetRound(int64(lastRound))
	blockResponse, err := apiclient.Operations.GetBlock(bParams, apiKeyQueryAuth)
	if err != nil {
		log.Fatal(err)
	}
	if blockResponse.Payload == nil {
		log.Fatal(fmt.Errorf("AlgoD API returned empty block response"))
	}
	block := *blockResponse.Payload
	fmt.Printf("\n-----------------Block Information-------------------\n")
	blockJSON, err := json.MarshalIndent(block, "", "\t")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(blockJSON))

	// Alternatively, we can also directly access block information:
	fmt.Printf("\n-----------------Protocol Version--------------------\n")
	fmt.Printf("CurrentProtocol=%s\n", *block.CurrentProtocol)
}

With main.go ready based on the above code, you should be able to run it using:

go run main.go

If that fails to build, ensure you updated the algorand/swagger-example path in the import statements.

You may also need to get the open-api libraries that swagger leverages:

go get -u github.com/open-api/...