Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetching Data from Indexers and Integrating it to a frontend interface #736

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 340 additions & 0 deletions docs/build/guides/dapps/indexers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
---
title: Fetching Data from Indexers and Integrating it to a frontend interface
---

## 1. What are Indexers?

Indexers in the Stellar ecosystem are specialized services that continuously process and organize blockchain data, making it easily accessible and queryable. They play a crucial role in data management and retrieval by providing a more efficient way to access information compared to directly querying the blockchain.

### Role of Indexers

- **Data Organization**: Indexers structure blockchain data into easily searchable formats.
- **Quick Retrieval**: They allow for fast and efficient querying of historical data.
- **Reduced Load**: By using indexers, applications can reduce the load on the Stellar network.

### Types of Data Provided by Indexers

Stellar indexers can provide various types of data, including:

- Account balances and history
- Transaction details
- Operation logs
- Trade history
- Asset information
- Ledger entries
- Events from contracts

## 2. Setting up Data Retrieval

### Connecting with an Indexer

1. **Choose an Indexer**: Select a reliable Stellar indexer. Some popular options include:

- **[Mercury](https://mercurydata.app/)**
- **[SubQuery](https://subquery.network/)**
- **[BlockEden](https://www.blockeden.xyz/)**

A more comprehensive list of supported indexers can be found in the [tools](/docs/tools/developer-tools#data-indexers) section

2. **API Documentation**: Familiarize yourself with the chosen indexer's API documentation.

3. **Authentication**: Some indexers may require API keys. Obtain necessary credentials if required.

4. **Setup HTTP/GraphQL Client**: Use a library like Axios, Fetch API, or Apollo Client to make HTTP requests to the indexer.

### Step-by-Step Instructions for Querying Data

We are going to use the [BlockEden](https://www.blockeden.xyz/) indexer for this example to query token metadata for all tokens indexed on the indexer sorted by recent on the soroban mainnet.

The goal is to query these data and display them in a frontend interface.

1. **Setup Account**:

- Sign up for an account on BlockEden: https://blockeden.xyz/dash/sign-up
- Create a new API key: https://blockeden.xyz/dash . This key will be used to authenticate requests to the indexer in step 3.

2. **GraphQL Playground**:

The graphQL playground has a user-friendly interface that allows you to test queries and explore the available data. It also has schema documentation that helps in understanding the structure of the data. We are interested in fetching the token metadata from the indexer so we will query that section.

- Open the GraphQL playground: https://blockeden.xyz/api-marketplace/stellar-soroban-indexer
- Use the following query to fetch the token metadata:

```graphql
query {
token_metadata(limit: 50, order_by: { updated_at: desc }) {
admin_address
name
contract_id
symbol
updated_at
decimal
}
}
```

This query fetches the token metadata for the latest 50 tokens indexed on the indexer.

The data displayed on this page can be safely integrated into our frontend application

## 3. Frontend Integration

This example will be using Vuejs, but the same principles can be applied to other frontend frameworks like React, Angular, or Svelte.

### Create a Vue application

```bash
npm create vue@latest
```

### Install dependencies

1. **Install the GraphQL client**:

```bash
npm install @apollo/client graphql @vue/apollo-composable
# tailwind css will be used for styling
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

The above libraries help in making GraphQL queries and managing the Apollo client in Vue applications.

### Setup Tailwind CSS

Add the following to the `tailwind.config.js` file:

```js
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
```

Add the following to the `assets/main.css` file:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Setup Application

Edit the `main.js` file to setup the Apollo client and provide it to the Vue app:

Notice how we are using the `import.meta.env` to access the environment variables in the Vite application.

```js
// main.js

import "./assets/main.css";
import {
ApolloClient,
InMemoryCache,
createHttpLink,
} from "@apollo/client/core";

import App from "./App.vue";
import { DefaultApolloClient } from "@vue/apollo-composable";
import { createApp } from "vue";

const apiToken = import.meta.env.VITE_API_TOKEN;

const httpLink = createHttpLink({
uri: `https://api.blockeden.xyz/stellar/mainnet/soroban/indexer/${apiToken}/v1/graphql`,
});

const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});

const app = createApp(App);

app.provide(DefaultApolloClient, apolloClient);
app.mount("#app");
```

Set the API token in the `.env` file:

```bash
# .env
VITE_API_TOKEN=token
```

### Displaying Data Effectively

We are going to create a component that fetches the token metadata from the indexer and displays it in the frontend.

Firstly, we will setup a basic table view to display the token metadata. This table is styled with [Tailwind CSS](https://tailwindcss.com/docs/installation) classes for a clean and responsive design.

We wil also implement pagination to manage the large dataset efficiently.

1. **components/TokenList.vue**:

```html
<template>
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Stellar Token List from BlockEden</h1>
<div v-if="loading" class="text-center">
<p class="text-lg">Loading...</p>
</div>
<div v-else-if="error" class="text-center text-red-500">
<p class="text-lg">Error: {{ error.message }}</p>
</div>
<div v-else>
<table class="w-full border-collapse border border-gray-300">
<thead>
<tr class="bg-gray-100">
<th class="p-2 border border-gray-300">Name</th>
<th class="p-2 border border-gray-300">Symbol</th>
<th class="p-2 border border-gray-300">Contract ID</th>
<th class="p-2 border border-gray-300">Admin Address</th>
<th class="p-2 border border-gray-300">Decimal</th>
<th class="p-2 border border-gray-300">Updated At</th>
</tr>
</thead>
<tbody>
<tr
v-for="token in tokenMetadata"
:key="token.contract_id"
class="hover:bg-gray-50"
>
<td class="p-2 border border-gray-300">{{ token.name }}</td>
<td class="p-2 border border-gray-300">{{ token.symbol }}</td>
<td class="p-2 border border-gray-300">{{ token.contract_id }}</td>
<td class="p-2 border border-gray-300">
{{ token.admin_address }}
</td>
<td class="p-2 border border-gray-300">{{ token.decimal }}</td>
<td class="p-2 border border-gray-300">
{{ new Date(token.updated_at).toLocaleString() }}
</td>
</tr>
</tbody>
</table>
<div class="mt-4 flex justify-between items-center">
<button
@click="prevPage"
:disabled="currentPage === 1"
class="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
Previous
</button>
<span>Page {{ currentPage }}</span>
<button
@click="nextPage"
:disabled="tokenMetadata.length < pageSize"
class="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
Next
</button>
</div>
</div>
</div>
</template>
```

This Vue.js template file renders a Stellar token list fetched from BlockEden's GraphQL API using Apollo Client and `@vue/apollo-composable`. It begins with a title and handles loading and error states while data is fetched asynchronously.

Once data is loaded, it populates a table with columns for token `name`, `symbol`, `contract_id`, `admin_address`, `decimal`, and `updated_at`. Pagination controls are provided with "Previous" and "Next" buttons that adjust the current page (`currentPage`) and trigger data refetching (`refetch`) based on the page size (`pageSize`). This setup ensures a responsive user interface for browsing through paginated token metadata effectively.

Now we will add the script section to fetch the data from the indexer and display it in the frontend:

```js
<script setup>
import { ref, watchEffect } from 'vue';
import { useQuery } from '@vue/apollo-composable';
import gql from 'graphql-tag';

const pageSize = 30;
const currentPage = ref(1);
const offset = ref(0);

const TOKEN_QUERY = gql`
query GetTokenMetadata($limit: Int!, $offset: Int!) {
token_metadata(limit: $limit, offset: $offset, order_by: { updated_at: desc }) {
admin_address
name
contract_id
symbol
updated_at
decimal
}
}
`;

const { result, loading, error, refetch } = useQuery(TOKEN_QUERY, {
limit: pageSize,
offset,
});

const tokenMetadata = ref([]);

watchEffect(() => {
if (result.value) {
tokenMetadata.value = result.value.token_metadata;
}
});

const nextPage = () => {
currentPage.value++;
offset.value += pageSize;
refetch();
};

const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
offset.value -= pageSize;
refetch();
}
};
</script>
```

The code above does fetching and paginating token metadata using GraphQL with Apollo Client and `@vue/apollo-composable`.

It sets up a query (`GetTokenMetadata`) to fetch metadata like `admin_address`, `name`, `symbol`, `updated_at`, and `decimal`, handling pagination via `limit` and `offset` parameters. The `useQuery` hook manages data loading (`loading`), result handling (`result`), and errors (`error`), while `watchEffect` keeps `tokenMetadata` synced with fetched results.

Pagination is achieved through `nextPage` and `prevPage` functions, adjusting `currentPage` and `offset` values and triggering a refresh (`refetch`) for navigating through token data pages seamlessly in Vue.js applications.

Next we import the component into `App.vue`

```html
<template>
<div class="flex h-screen bg-gray-100">
<TokenList />
</div>
</template>

<script setup>
import TokenList from "@/components/TokenList.vue";
</script>
```

```bash
npm run dev
```

### App is ready

We were able to fetch data from the indexer and display it in a frontend interface. The data is paginated to manage the large dataset efficiently.

### Security Concerns:

Ensure that sensitive data like API keys are stored securely and not exposed in the frontend code. Using a backend or serverless function to fetch data from the indexer can help protect sensitive information.

### Conclusion

By following the steps outlined above, you can effectively fetch data from Stellar indexers and integrate it into a frontend interface. This approach allows you to build powerful applications that leverage the rich data provided by indexers.

### Demo

You can find a working demo of this frontend integration [here](https://stellar-indexed.web.app). and the complete code [here](https://github.com/Myestery/stellar-indexed)
Loading