# Graph Node Requests

## Prerequisites

For this section, you will need:

* A user's Theta Network wallet address, see the previous page on how to obtain this
* A HTTP request library installed, such as [axios](https://www.npmjs.com/package/axios)
* The smart contract address(es) of your event

## Querying the GraphQL backend

We have a [GraphQL playground](https://graphql.tkets.io/subgraphs/name/tkets-core/graphql) for you to send requests directly before integrating this into your platform.

To start, try sending the following request using the playground:

```graphql
query {
  ticketTokens (where: {
      owner: "0x059377c014cfc12dd2612ebfe9cfd1a6fc1a8883", 
      ticket_in: [
        "0x0478578c5e906afeb1bdbbf358929affbf1575c8",
        "0xaa7fc9c591eab1f80e7e29a1f88ee144c6a3694f"
       ]
     }) 
  {
    owner { id },
    tokenID
  
}
```

The above request searches all of our ticket tokens where the owner address is `0x059377c014cfc12dd2612ebfe9cfd1a6fc1a8883` and the ticket smart contract address is either `0x0478578c5e906afeb1bdbbf358929affbf1575c8` or `0xaa7fc9c591eab1f80e7e29a1f88ee144c6a3694f`.

## Searching for past transactions

Let's try something more advanced now, and try to find all of the past transactions of a ticket. Try sending the following request to the playground:

```graphql
query {
  transfers (where: {ticketToken: "0x0478578c5e906afeb1bdbbf358929affbf1575c8#65"}) {
    from,
    to,
    ticketToken {
      tokenID,
      ticket {
        id
      },
      owner {
        id
      }
    }
  }
}
```

This searches the database for all transfers that had taken place for the ticket with smart contract address `0x0478578c5e906afeb1bdbbf358929affbf1575c8` and token ID `65`. It returns the address from which it was transferred, the address it was transferred to, as well as the current owner and token ID of the ticket.

## Querying Metapass platform data

Next, let's try the following query:

```graphql
query {
  tketsdayDatas (where: {date_gt: 1635752657}, orderBy: date, orderDirection: desc, first: 10) {
    date,
    dailyTxns,
    dailyVolumeTFUEL,
    totalVolumeTFUEL,
    eventCount
  }
}
```

This query checks the daily data collated about the platform, and finds the first 10 entries corresponding to a date greater than a timestamp of `1635752657`, ordered by descending date. It returns the date of the entry, the number of daily transactions, the total and daily volume of TFUEL transacted, as well as the event count.

By now, you should have a basic understanding of how the query system works, and can construct your own queries to suit the information you need. You can refer to the Graph Node API guide for a full schema of the data indexed by the Graph node, or also read more in the [GraphQL API docs](https://thegraph.com/docs/en/developer/graphql-api/) for more information about the query system.

## Querying by HTTP request

Now, with your query crafted, you can query the database programmatically using a HTTP POST request rather than doing it manually in the playground. This also allows you to set any variables within your query.

## Query the GraphQL database

<mark style="color:green;">`POST`</mark> `https://graphql.tkets.io/subgraphs/name/tkets-core/graphql/`

Submits a query to the GraphQL database with the specified variables, and returns a JSON response with the result objects

#### Request Body

| Name                                    | Type   | Description                                               |
| --------------------------------------- | ------ | --------------------------------------------------------- |
| query<mark style="color:red;">\*</mark> | String | Your query (as above), in a plaintext string              |
| variables                               | JSON   | (Optional) Variables within the query that can be defined |

{% tabs %}
{% tab title="200: OK JSON response with objects specifieid by the query" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

Make sure to use a POST method to submit the request. Mutations are not allowed because of restrictions on the graph node, and therefore the database is read only.

{% hint style="info" %}

#### Securing your backend endpoints

For protected endpoints that require only users who are authenticated (for example, an endpoint that allows users who hold NFTs to change their name on your platform or make a vote), you will need to check on both your frontend and backend if they are indeed holders of your NFT.&#x20;

This can be done with the GraphQL queries on this page, as well as a signature verification on your backend. See [signature verification](https://docs.metapass.world/miscellaneous#signature-verification) for more details
{% endhint %}

For example, you may use the following code to submit a request:

{% tabs %}
{% tab title="React TSX" %}

```tsx
import axios from 'axios'

const GRAPHQL_ADDRESS = 'https://graphql.tkets.io'
const GRAPHQL_LIMIT = 100

// This query finds the smart contract addresses of tickets
// that an account owns
const QUERY_OWNED_TICKETS_OF_ACCOUNT = `
  query ($ownerAddress: ID!, $skipNumber: Int!) {
    ticketTokens (where: {owner: $ownerAddress}, skip: $skipNumber) {
      ticket {
        id
      }
    }
  }
`

// Main function to call
export function getOwnedTicketsOfAccount(account: string) {
  return tryGetOwnedTicketsOfAccountWithSkip(account, 0, [])
}

// Helper function, can be called recursively with an accumulator
export async function tryGetOwnedTicketsOfAccountWithSkip(address: string, skip: number, accumulator: any[]) : Promise<string[]> {
  return axios.post(`${GRAPHQL_ADDRESS}/subgraphs/name/tkets-core`, 
    { 
      query: QUERY_OWNED_TICKETS_OF_ACCOUNT, 
      variables: {
        ownerAddress: address.toLowerCase(),
        skipNumber: skip
      }
    }
  ).then((r) => {
    if (r.status === 200) {
      // convert JSON result into a list of ticket smart contract address strings
      const ticketsParsed = r.data.data.ticketTokens.map((ticketToken: any) => {
        return ticketToken.ticket.id as string
      })

      // add result to the accumulator
      accumulator = accumulator.concat(ticketsParsed)

      // check if we have reached the GraphQL query limit of 100
      // if so, we need to submit another request with the skip variable
      // to get the next 100 ticket smart contract addresses
      if (r.data.data.ticketTokens.length === GRAPHQL_LIMIT) {
        return tryGetOwnedTicketsOfAccountWithSkip(address, skip + GRAPHQL_LIMIT, accumulator)
      }

      // Convert to set in order to remove any duplicates
      const ticketParsedSet = Array.from(new Set(accumulator))
      
      return ticketParsedSet as string[]
    }

    return [] as string[]
  }).catch((e: Error) => {
    return [] as string[]
  })
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

GRAPHQL_ADDRESS = 'https://graphql.tkets.io'
GRAPHQL_LIMIT = 100

QUERY_TICKET_HOLDER = '''
  query ($ownerAddress: ID!, $skipNumber: Int!) {
    ticketTokens (where: {owner: $ownerAddress}, skip: $skipNumber) {
      ticket {
        id
      }
    }
  }
'''

def get_owned_tickets_of_account(address, skip=0, accumulator=None):
    accumulator = accumulator or []
    ticket_set = []
    
    try:
        holder_response = requests.post(f"{GRAPHQL_ADDRESS}/subgraphs/name/tkets-core", json={
            "query": QUERY_TICKET_HOLDER,
            "variables": {
                "ownerAddress": address.lower(),
                "skipNumber": skip
            }
        })
        
        for ticket_json in holder_response["data"]["ticketTokens"]:
          accumulator.append(ticket_json["ticket"]["id"])
        
        if (len(holder_response["data"]["ticketTokens"]) === GRAPHQL_LIMIT) {
          return get_owned_tickets_of_account(address, skip + GRAPHQL_LIMIT, accumulator)
        }
        
        ticket_set = list(set(accumulator))
    except:
        # error retrieving GraphQL, try again later
        raise
        
    return ticket_set
```

{% endtab %}
{% endtabs %}
