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

  1. Create your account on dfuse.eosnation.io
  2. Click “Create New Key” and give it a name, a category. In the case of a web key give it an “Origin” value.
See Authentication for further details

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 }

<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">StatusCode</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">200</span> {
	<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;unable to obtain token, status not 200, got %d: %s&#34;</span>, <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">StatusCode</span>, <span style="color:#a6e22e">reqBody</span>.<span style="color:#a6e22e">String</span>())
	<span style="color:#66d9ef">return</span>
}

<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">body</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadAll</span>(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
	<span style="color:#a6e22e">token</span> = <span style="color:#a6e22e">gjson</span>.<span style="color:#a6e22e">GetBytes</span>(<span style="color:#a6e22e">body</span>, <span style="color:#e6db74">&#34;token&#34;</span>).<span style="color:#a6e22e">String</span>()
	<span style="color:#a6e22e">expiration</span> = <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Unix</span>(<span style="color:#a6e22e">gjson</span>.<span style="color:#a6e22e">GetBytes</span>(<span style="color:#a6e22e">body</span>, <span style="color:#e6db74">&#34;expires_at&#34;</span>).<span style="color:#a6e22e">Int</span>(), <span style="color:#ae81ff">0</span>)
}
<span style="color:#66d9ef">return</span>

}


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()

<span style="color:#66d9ef">if</span> response<span style="color:#f92672">.</span>status <span style="color:#f92672">!=</span> <span style="color:#ae81ff">200</span>:
    <span style="color:#66d9ef">raise</span> <span style="color:#a6e22e">Exception</span>(<span style="color:#e6db74">&#34; Status: </span><span style="color:#e6db74">%s</span><span style="color:#e6db74"> reason: </span><span style="color:#e6db74">%s</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">%</span> (response<span style="color:#f92672">.</span>status, response<span style="color:#f92672">.</span>reason))

token <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>loads(response<span style="color:#f92672">.</span>read()<span style="color:#f92672">.</span>decode())[<span style="color:#e6db74">&#39;token&#39;</span>]
connection<span style="color:#f92672">.</span>close()

<span style="color:#66d9ef">return</span> 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 docs/quickstarts/go

git clone https://github.com/EOS-Nation/dfuse-docs
cd 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") }

<span style="color:#a6e22e">token</span>, <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">getToken</span>(<span style="color:#a6e22e">dfuseAPIKey</span>)
<span style="color:#a6e22e">panicIfError</span>(<span style="color:#a6e22e">err</span>)

<span style="color:#a6e22e">credential</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">oauth</span>.<span style="color:#a6e22e">NewOauthAccess</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">oauth2</span>.<span style="color:#a6e22e">Token</span>{<span style="color:#a6e22e">AccessToken</span>: <span style="color:#a6e22e">token</span>, <span style="color:#a6e22e">TokenType</span>: <span style="color:#e6db74">&#34;Bearer&#34;</span>})
<span style="color:#a6e22e">transportCreds</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">credentials</span>.<span style="color:#a6e22e">NewClientTLSFromCert</span>(<span style="color:#66d9ef">nil</span>, <span style="color:#e6db74">&#34;&#34;</span>)
<span style="color:#a6e22e">conn</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">grpc</span>.<span style="color:#a6e22e">Dial</span>(<span style="color:#a6e22e">endpoint</span>,
	<span style="color:#a6e22e">grpc</span>.<span style="color:#a6e22e">WithPerRPCCredentials</span>(<span style="color:#a6e22e">credential</span>),
	<span style="color:#a6e22e">grpc</span>.<span style="color:#a6e22e">WithTransportCredentials</span>(<span style="color:#a6e22e">transportCreds</span>),
)
<span style="color:#a6e22e">panicIfError</span>(<span style="color:#a6e22e">err</span>)

<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">pb</span>.<span style="color:#a6e22e">NewGraphQLClient</span>(<span style="color:#a6e22e">conn</span>)

}


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 <span style="color:#f92672">=</span> grpc<span style="color:#f92672">.</span>secure_channel(endpoint,
    credentials <span style="color:#f92672">=</span> grpc<span style="color:#f92672">.</span>composite_channel_credentials(
        grpc<span style="color:#f92672">.</span>ssl_channel_credentials(),
        grpc<span style="color:#f92672">.</span>access_token_call_credentials(get_token(dfuse_api_key))
))

<span style="color:#66d9ef">return</span> graphql_pb2_grpc<span style="color:#f92672">.</span>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 { </span><span style="color:#e6db74"> searchTransactionsForward(query:&#34;receiver:eosio.token action:transfer -data.quantity:&#39;0.0001 EOS&#39;&#34;) { </span><span style="color:#e6db74"> undo cursor </span><span style="color:#e6db74"> trace { id matchingActions { json } } </span><span style="color:#e6db74"> } </span><span style="color:#e6db74">}

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)

<span style="color:#66d9ef">for</span> {
	<span style="color:#a6e22e">resp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">executor</span>.<span style="color:#a6e22e">Recv</span>()
	<span style="color:#a6e22e">panicIfError</span>(<span style="color:#a6e22e">err</span>)

	<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Errors</span>) &gt; <span style="color:#ae81ff">0</span> {
        <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Errors</span> {
            <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Request failed: %s\n&#34;</span>, <span style="color:#a6e22e">err</span>)
        }

        <span style="color:#75715e">/* We continue here, but you could take another decision here, like exiting the process */</span>
        <span style="color:#66d9ef">continue</span>
	}

	<span style="color:#a6e22e">document</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">eosioDocument</span>{}
	<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>([]byte(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Data</span>), <span style="color:#a6e22e">document</span>)
	<span style="color:#a6e22e">panicIfError</span>(<span style="color:#a6e22e">err</span>)

	<span style="color:#a6e22e">result</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">document</span>.<span style="color:#a6e22e">SearchTransactionsForward</span>
	<span style="color:#a6e22e">reverted</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;&#34;</span>
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">Undo</span> {
        <span style="color:#a6e22e">reverted</span> = <span style="color:#e6db74">&#34; REVERTED&#34;</span>
	}

	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">action</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">Trace</span>.<span style="color:#a6e22e">MatchingActions</span> {
        <span style="color:#a6e22e">data</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">action</span>.<span style="color:#a6e22e">JSON</span>
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Transfer %s -&gt; %s [%s]%s\n&#34;</span>, <span style="color:#a6e22e">data</span>[<span style="color:#e6db74">&#34;from&#34;</span>], <span style="color:#a6e22e">data</span>[<span style="color:#e6db74">&#34;to&#34;</span>], <span style="color:#a6e22e">data</span>[<span style="color:#e6db74">&#34;quantity&#34;</span>], <span style="color:#a6e22e">reverted</span>)
	}
}

}


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))

<span style="color:#66d9ef">for</span> rawResult <span style="color:#f92672">in</span> stream:
    <span style="color:#66d9ef">if</span> rawResult<span style="color:#f92672">.</span>errors:
        <span style="color:#66d9ef">print</span>(<span style="color:#e6db74">&#34;An error occurred&#34;</span>)
        <span style="color:#66d9ef">print</span>(rawResult<span style="color:#f92672">.</span>errors)
    <span style="color:#66d9ef">else</span>:
        result <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>loads(rawResult<span style="color:#f92672">.</span>data)
        <span style="color:#66d9ef">for</span> action <span style="color:#f92672">in</span> result[<span style="color:#e6db74">&#39;searchTransactionsForward&#39;</span>][<span style="color:#e6db74">&#39;trace&#39;</span>][<span style="color:#e6db74">&#39;matchingActions&#39;</span>]:
            undo <span style="color:#f92672">=</span> result[<span style="color:#e6db74">&#39;searchTransactionsForward&#39;</span>][<span style="color:#e6db74">&#39;undo&#39;</span>]
            data <span style="color:#f92672">=</span> action[<span style="color:#e6db74">&#39;json&#39;</span>]
            <span style="color:#66d9ef">print</span>(<span style="color:#e6db74">&#34;Transfer </span><span style="color:#e6db74">%s</span><span style="color:#e6db74"> -&gt; </span><span style="color:#e6db74">%s</span><span style="color:#e6db74"> [</span><span style="color:#e6db74">%s</span><span style="color:#e6db74">]</span><span style="color:#e6db74">%s</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">%</span> (data[<span style="color:#e6db74">&#39;from&#39;</span>], data[<span style="color:#e6db74">&#39;to&#39;</span>], data[<span style="color:#e6db74">&#39;quantity&#39;</span>], <span style="color:#e6db74">&#34; REVERTED&#34;</span> <span style="color:#66d9ef">if</span> undo <span style="color:#66d9ef">else</span> <span style="color:#e6db74">&#34;&#34;</span>))

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"

<span style="color:#a6e22e">pb</span> <span style="color:#e6db74">&#34;github.com/dfuse-io/docs/quickstarts/go/pb&#34;</span>
<span style="color:#e6db74">&#34;github.com/tidwall/gjson&#34;</span>
<span style="color:#e6db74">&#34;golang.org/x/oauth2&#34;</span>
<span style="color:#e6db74">&#34;google.golang.org/grpc&#34;</span>
<span style="color:#e6db74">&#34;google.golang.org/grpc/credentials&#34;</span>
<span style="color:#e6db74">&#34;google.golang.org/grpc/credentials/oauth&#34;</span>

)


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 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 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

7. What’s next?

API References

Other