Quick Start: Other Languages
dfuse exposes its data through a GraphQL-over-gRPC interface. The protobuf files are in this GitHub repository .
The code from the examples on this page can be found in the quickstarts folder of this docs GitHub repository .
1. Get a dfuse API Key
Get an API key
- Create your account on dfuse.eosnation.io
-
Click “Create New Key” and give it a name, a category. In the case of a
web
key give it an “Origin” value.
2. Generate a JWT from your API key
The JWT is a token with a short expiration period, used to communicate with dfuse services. You will have to implement token caching and manage renewal upon expiration. See Authentication for more details.
func getToken(apiKey string) (token string, expiration time.Time, err error) {
reqBody := bytes.NewBuffer([]byte(fmt.Sprintf(`{"api_key":"%s"}`, apiKey)))
resp, err := http.Post("https://auth.eosnation.io/v1/auth/issue", "application/json", reqBody)
if err != nil {
err = fmt.Errorf("unable to obtain token: %s", err)
return
}
if resp.StatusCode != 200 {
err = fmt.Errorf("unable to obtain token, status not 200, got %d: %s", resp.StatusCode, reqBody.String())
return
}
if body, err := ioutil.ReadAll(resp.Body); err == nil {
token = gjson.GetBytes(body, "token").String()
expiration = time.Unix(gjson.GetBytes(body, "expires_at").Int(), 0)
}
return
}
def get_token(api_key):
connection = HTTPSConnection("auth.eosnation.io")
connection.request('POST', '/v1/auth/issue', json.dumps({"api_key": api_key}), {'Content-type': 'application/json'})
response = connection.getresponse()
if response.status != 200:
raise Exception(" Status: %s reason: %s" % (response.status, response.reason))
token = json.loads(response.read().decode())['token']
connection.close()
return token
curl https://auth.eosnation.io/v1/auth/issue -s \
--data-binary '{"api_key":"server_abcdef12345678900000000000"}'
3. Get the client stub and dependencies for your language
The protobuf files defining our GraphQL-over-gRPC interface are available in this GitHub repository .
A lot of languages provide tools to generate client stubs from protobuf files, as you can find in the official gRPC documentation .
For your convenience, we also provide pre-generated client stubs for some languages. The code from the examples on this page can be found in the quickstarts folder of this docs GitHub repository .
git clone https://github.com/EOS-Nation/dfuse-docs
cd dfuse-docs/quickstarts/go
git clone https://github.com/EOS-Nation/dfuse-docs
cd dfuse-docs/quickstarts/python
python -m pip install grpcio-tools --ignore-installed
# On MacOS
brew install grpcurl
# On Linux/Windows
go get github.com/fullstorydev/grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl
# Download from Git
git clone https://github.com/dfuse-io/graphql-over-grpc
# Download from a Zip archive
curl -sLO https://github.com/dfuse-io/graphql-over-grpc/archive/master.zip
unzip -q master.zip
# Generate your code
cd graphql-over-grpc
protoc graphql/graphql.proto # add your language-specific flags here
4. Create the client
Now that you have generated the client stub (or picked the generated one), we can define the client creation code. The client can be re-used across all of the requests and streams you need to do, it should be properly cached at the appropriate level for your use case.
func createClient(endpoint string) pb.GraphQLClient {
dfuseAPIKey := os.Getenv("DFUSE_API_KEY")
if dfuseAPIKey == "" {
panic("you must specify a DFUSE_API_KEY environment variable")
}
token, _, err := getToken(dfuseAPIKey)
panicIfError(err)
credential := oauth.NewOauthAccess(&oauth2.Token{AccessToken: token, TokenType: "Bearer"})
transportCreds := credentials.NewClientTLSFromCert(nil, "")
conn, err := grpc.Dial(endpoint,
grpc.WithPerRPCCredentials(credential),
grpc.WithTransportCredentials(transportCreds),
)
panicIfError(err)
return pb.NewGraphQLClient(conn)
}
def create_client(endpoint):
dfuse_api_key = os.environ.get("DFUSE_API_KEY")
if dfuse_api_key == None:
raise Exception("you must specify a DFUSE_API_KEY environment variable")
channel = grpc.secure_channel(endpoint,
credentials = grpc.composite_channel_credentials(
grpc.ssl_channel_credentials(),
grpc.access_token_call_credentials(get_token(dfuse_api_key))
))
return graphql_pb2_grpc.GraphQLStub(channel)
5. Stream your first results
Let’s first define the GraphQL operation, as a string, that we will use to open a GraphQL subscription. This element tells the backend server which fields to return to you, as you get to pick and choose only what you are interested in.
Note
Want to inspect the full set of available fields you can retrieve?
const operationEOS = `subscription {
searchTransactionsForward(query:"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'") {
undo cursor
trace { id matchingActions { json } }
}
}`
type eosioDocument struct {
SearchTransactionsForward struct {
Cursor string
Undo bool
Trace struct {
ID string
MatchingActions []struct {
JSON map[string]interface{}
}
}
}
}
OPERATION_EOS = """subscription {
searchTransactionsForward(query:"receiver:eosio.token action:transfer") {
undo cursor
trace { id matchingActions { json } }
}
}"""
And we can finally define the code needed to perform your first stream using dfuse Search. This snippet initiates the connection with dfuse servers and starts streaming transfers forever.
func streamEOSIO(ctx context.Context) {
/* The client can be re-used for all requests, cache it at the appropriate level */
client := createClient("eos.dfuse.eosnation.io:9000")
executor, err := client.Execute(ctx, &pb.Request{Query: operationEOS})
panicIfError(err)
for {
resp, err := executor.Recv()
panicIfError(err)
if len(resp.Errors) > 0 {
for _, err := range resp.Errors {
fmt.Printf("Request failed: %s\n", err)
}
/* We continue here, but you could take another decision here, like exiting the process */
continue
}
document := &eosioDocument{}
err = json.Unmarshal([]byte(resp.Data), document)
panicIfError(err)
result := document.SearchTransactionsForward
reverted := ""
if result.Undo {
reverted = " REVERTED"
}
for _, action := range result.Trace.MatchingActions {
data := action.JSON
fmt.Printf("Transfer %s -> %s [%s]%s\n", data["from"], data["to"], data["quantity"], reverted)
}
}
}
def stream_eosio():
# The client can be re-used for all requests, cache it at the appropriate level
client = create_client('eos.dfuse.eosnation.io:9000')
stream = client.Execute(Request(query = OPERATION_EOS))
for rawResult in stream:
if rawResult.errors:
print("An error occurred")
print(rawResult.errors)
else:
result = json.loads(rawResult.data)
for action in result['searchTransactionsForward']['trace']['matchingActions']:
undo = result['searchTransactionsForward']['undo']
data = action['json']
print("Transfer %s -> %s [%s]%s" % (data['from'], data['to'], data['quantity'], " REVERTED" if undo else ""))
And here is a sample of the prints you will receive from the standard output after running the example above:
Transfer eosbetdice11 -> eosbetbank11 [0.0500 EOS]
Transfer newdexpublic -> gq4tcnrwhege [2.8604 EOS]
Transfer wpwpwp222222 -> eosioeosios3 [20.0000 EOS]
Transfer wallet.bg -> bulls.bg [0.9000 EOS]
Transfer bluebetproxy -> bluebetbulls [0.6000 EOS]
...
6. Full working examples
Here is the small glue code containing the main
function, imports and other helper functions to run the example:
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
pb "github.com/dfuse-io/docs/quickstarts/go/pb"
"github.com/tidwall/gjson"
"golang.org/x/oauth2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/oauth"
)
try:
# python3
from http.client import HTTPSConnection
except ImportError:
# python2
from httplib import HTTPSConnection
import grpc
import json
import os
import ssl
import sys
from graphql import graphql_pb2_grpc
from graphql.graphql_pb2 import Request
If you prefer, you can directly clone our ready-made repository with all the quick start examples:
git clone https://github.com/EOS-Nation/dfuse-docs
cd dfuse-docs/quickstarts/go
# Replace 'server_abcdef12345678900000000000' with your own API key!
DFUSE_API_KEY="server_abcdef12345678900000000000" go run main.go eosio
git clone https://github.com/EOS-Nation/dfuse-docs
cd dfuse-docs/quickstarts/python
python -m pip install grpcio-tools --ignore-installed
# Replace 'server_abcdef12345678900000000000' with your own API key!
DFUSE_API_KEY="server_abcdef12345678900000000000" python main.py eosio