JavaScript Quickstart

In this guide we will show you how to create a basic setup so that you can benefit from the dfuse GraphQL API under one of the supported JavaScript environments:

  • Browser through a bundler like Webpack (includes Create React App projects) (Bundler code tab)
  • Browser standalone (Browser code tab)
  • Node.js server (Node.js code tab)

Note

While not yet in the supported list, you should be able to use the example under a React Native environment.

All examples uses ES6 syntax with await/async keywords, using import keywords on Bundler and Browser environments while using the require syntax on Node.js environment. However, the library compiles itself to down to ES5 features, so we support older ES5 compliant browsers that are not compatible with ES6 features (IE 11 for example).

We assume the commands below are performed in an empty project folder. To quickly start an empty project:


mkdir -p example-dfuse-javascript
cd example-dfuse-javascript
npm init -y

mkdir -p example-dfuse-javascript
cd example-dfuse-javascript
yarn init -y

1. Get a dfuse API Key

Get an API key

  1. Create your account on https://app.dfuse.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. Adding the Client Library

The simplest way to get started with dfuse and JavaScript/TypeScript development is to use the dfuse JS client library .

Here are a few of its key features:

  • Handles API token issuance
  • Refreshes your API token upon expiration
  • Automatically reconnects if the connection closes
  • Supports Browsers and Node.js environments

You can add it to your project using Yarn or NPM.


npm install @dfuse/client

yarn add @dfuse/client

Node.js Extra Steps

If you are targeting the Node.js environment, a few extra steps are required to be able to use the @dfuse/client library. The library relies on the node-fetch package for HTTP requests and on the ws package for WebSocket connections.


npm install node-fetch ws

yarn add node-fetch ws

Once installed, prior to calling anything else, ensure that global.fetch and global.WebSocket are set in the global scope.

Important

This is required only in a Node.js environment. When targeting a Browser environment (in standalone HTML or through a bundler, @dfuse/client library automatically uses fetch and WebSocket objects provided by the browser).

global.fetch = require('node-fetch')
global.WebSocket = require('ws')

Note

You prefer to not pollute the global scope? Check Node.js Configuration Example to see how you can pass the options directly when instantiating the client instead of polluting the global scope.

3. Create the client

With the initial setup complete, you can start coding. The first thing we will do is initialize the dfuse client using the API key you created in the first step and the network you want to connect to.

Valid networks can be found at EOSIO API Endpoints


const { createDfuseClient } = require("@dfuse/client")

const client = createDfuseClient({
  apiKey: process.env.DFUSE_API_KEY,
  network: "mainnet.eos.dfuse.io",
})

import { createDfuseClient } from "@dfuse/client"

const client = createDfuseClient({
  apiKey: process.env.DFUSE_API_KEY,
  network: "mainnet.eos.dfuse.io",
})

<head>
    <style> li { font-family: monospace; margin: 0.15; }</style>
    <script src="https://unpkg.com/@dfuse/client"></script>
    <script>
        const client = dfuseClient.createDfuseClient({
          // Replace 'web_abcdef12345678900000000000' with your own API key!
          apiKey: 'web_abcdef12345678900000000000',
          network: 'mainnet.eos.dfuse.io'
        })
    </script>
</head>

4. Stream your first results

Let’s first define the GraphQL operation, as a string, that we will use to perform GraphQL subscription. This element tells the backend server what fields to return to you, you get to choose and pick only what you are interested in.

Note

Want to inspect the full set of available fields you can retrieve?


// You must use a `$cursor` variable so stream starts back at last marked cursor on reconnect!
const operation = `subscription($cursor: String!) {
  searchTransactionsForward(query:"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'", cursor: $cursor) {
    undo cursor
    trace { id matchingActions { json } }
  }
}`

// You must use a `$cursor` variable so stream starts back at last marked cursor on reconnect!
const operation = `subscription($cursor: String!) {
  searchTransactionsForward(query:"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'", cursor: $cursor) {
    undo cursor
    trace { id matchingActions { json } }
  }
}`

<script>
// You must use a `$cursor` variable so stream starts back at last marked cursor on reconnect!
const operation = `subscription($cursor: String!) {
  searchTransactionsForward(query:"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'", cursor: $cursor) {
    undo cursor
    trace { id matchingActions { json } }
  }
}`
</script>

Next, you create the GraphQL subscription to stream transfers as they come. You will use the searchTransactionsForward operation, with the "receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'" query (See the Search Query Language reference here). This basically means, give me all transactions containing one or more actions named transfer executed by the eosio.token account for which the quantity field of the action is not 0.0001 EOS.

You can combine the dfuse client instance we created in step 3 with the GraphQL document we defined above in a main function:


async function main() {
  const stream = await client.graphql(operation, (message) => {
    if (message.type === "data") {
      const { undo, cursor, trace: { id, matchingActions }} = message.data.searchTransactionsForward
      matchingActions.forEach(({ json: { from, to, quantity } }) => {
        console.log(`Transfer ${from} -> ${to} [${quantity}]${undo ? " REVERTED" : ""}`)
      })

      // Mark stream at cursor location, on re-connect, we will start back at cursor
      stream.mark({ cursor })
    }

    if (message.type === "error") {
      console.log("An error occurred", message.errors, message.terminal)
    }

    if (message.type === "complete") {
      console.log("Completed")
    }
  })

  // Waits until the stream completes, or forever
  await stream.join()
  await client.release()
}

// You would normally use your framework entry point and render using components,
// we are using pure HTML manipulation for sake of example simplicity.
async function main() {
  const stream = await client.graphql(operation, (message) => {
    if (message.type === "data") {
      const { undo, cursor, trace: { id, matchingActions }} = message.data.searchTransactionsForward
      matchingActions.forEach(({ json: { from, to, quantity } }) => {
        const paragraphNode = document.createElement("li")
        paragraphNode.innerText = `Transfer ${from} -> ${to} [${quantity}]${undo ? " REVERTED" : ""}`

        document.body.prepend(paragraphNode)
      })

      // Mark stream at cursor location, on re-connect, we will start back at cursor
      stream.mark({ cursor })
    }

    if (message.type === "error") {
      const { errors, terminal } = message
      const paragraphNode = document.createElement("li")
      paragraphNode.innerText = `An error occurred ${JSON.stringify({ errors, terminal })}`

      document.body.prepend(paragraphNode)
    }

    if (message.type === "complete") {
        const paragraphNode = document.createElement("li")
        paragraphNode.innerText = "Completed"

        document.body.prepend(paragraphNode)
    }
  })

  // Waits until the stream completes, or forever
  await stream.join()
  await client.release()
}

<script>
async function main() {
  const stream = await client.graphql(operation, (message) => {
    if (message.type === "data") {
      const { undo, cursor, trace: { id, matchingActions }} = message.data.searchTransactionsForward
      matchingActions.forEach(({ json: { from, to, quantity } }) => {
        const paragraphNode = document.createElement("li")
        paragraphNode.innerText = `Transfer ${from} -> ${to} [${quantity}]${undo ? " REVERTED" : ""}`

        document.body.prepend(paragraphNode)
      })

      // Mark stream at cursor location, on re-connect, we will start back at cursor
      stream.mark({ cursor })
    }

    if (message.type === "error") {
      const { errors, terminal } = message
      const paragraphNode = document.createElement("li")
      paragraphNode.innerText = `An error occurred ${JSON.stringify({ errors, terminal })}`

      document.body.prepend(paragraphNode)
    }

    if (message.type === "complete") {
        const paragraphNode = document.createElement("li")
        paragraphNode.innerText = "Completed"

        document.body.prepend(paragraphNode)
    }
  })

  // Waits until the stream completes, or forever
  await stream.join()
  await client.release()
}
</script>

The function passed as the 2nd parameter to client.graphql() will be called every time a new result is returned by the API. And here a sample of the prints you will receive as a result of executing the streaming operation 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]
...

5. Full Working Examples

Here the small glue code containing the main function, imports and other helper functions to run the example:


main().catch((error) => console.log("Unexpected error", error))

main().catch((error) => document.body.innerHTML = `<p>${error}</p>`)

<script>
main().catch((error) => document.body.innerHTML = `<p>${error}</p>`)
</script>

git clone https://github.com/dfuse-io/docs
cd docs/quickstarts/javascript/node.js
npm install

# Replace 'server_abcdef12345678900000000000' with your own API key!
DFUSE_API_KEY=server_abcdef12345678900000000000 node index.eosio.js

git clone https://github.com/dfuse-io/docs
cd docs/quickstarts/javascript/bundler
npm install

# Replace 'web_abcdef12345678900000000000' with your own API key!
DFUSE_API_KEY=web_abcdef12345678900000000000 npm run build:eosio

# Open `index.eosio.html` directly in your favorite Browser
open index.eosio.html       # Mac
xdg-open index.eosio.html   # Ubuntu
start index.eosio.thml      # Windows

git clone https://github.com/dfuse-io/docs
cd docs/quickstarts/javascript/browser
# Manually edit index.eosio.html changing `web_abcdef12345678900000000000` with your own API key

# Open `index.eosio.html` directly in your favorite Browser
open index.eosio.html       # Mac
xdg-open index.eosio.html   # Ubuntu
start index.eosio.thml      # Windows

6. What’s next?