Resource Limitations

The Levain GraphQL API has limitations in place to protect against excessive or abusive calls to Levain's GraphQL servers. A single GraphQL query can potentially generate a huge workload for a server, like thousands of database operations or API calls. In order to limit and keep track of what each GraphQL operation can do, a set of rules are applied to each query and mutation to estimate its complexity and execution time. If a query exceeds the defined limit, an error is thrown.

The resource limitations will change over time as we learn more about the usage patterns of the GraphQL API. To ensure that your application is not affected by these changes, we recommend that you always specify reasonable limits on your queries and mutations.

By design, GraphQL resource limits are always higher than the equivalent REST API limits due to the nature of GraphQL hierarchical queries.

Complexity Limit

The complexity limit is a limit on the computational complexity of a GraphQL query. It is designed to protect against queries that are computationally expensive and may take a long time to execute. Currently, the complexity limit is set to 50,000 per query.

The complexity of a GraphQL query is calculated by summing up the complexity of each field in the query. The complexity of a field is calculated by multiplying the complexity of the field by the number of items returned by the field.

Complexity Calculation

  • NODE = 1 - A node within a connection.
  • FIELD = 1 - A field that loads data from the database within the same row or with simple join.
  • AUTH = 100 - A query that computes the authorization of the user for a resource.
  • API = 500 - A field that loads data from an API that requires additional API calls to load the data.

Different fields in a GraphQL query have different complexity values. For example, a field that loads data from the database has a complexity of 1 while a field that loads data from an external API has a complexity of 500.

query {
  # Complexity = 100 + 1 + 603 = 704
  # AUTH = 100
  organization(orgId: "012345678912") {
    # FIELD = 1
    name
    # Complexity = 100 + 502 + 1 = 603
    # AUTH = 100
    wallet(walletId: "0") {
      # FIELD = 1
      name
      # Complexity = 500 + 1 + 1 = 502
      balanceByAssetId(assetId: "0") {
        # API = 500
        networkAsset {
          # FIELD = 1
          name
        }
        # FIELD = 1
        amount
      }
    }
    # Complexity = 10 x 3 = 30
    networks(first: 10) {
      # NODE = 1
      edges {
        # NODE = 1
        node {
          # FIELD = 1
          networkId
        }
      }
    }
  }
}

The estimated complexity of the query above is 704 which is within the complexity limit of 50,000. While the query above could easily be calculated by hand, it is not always easy to calculate the complexity of a query due to estimations and assumptions that need to be made. For your convenience, you should always only query what you need, never more and paginate reasonably.

Pagination Limit

The pagination limit is a limit on the number of items that can be returned in a single page of a paginated query per connection. This is applied to all paginated queries on top of the complexity limit to protect against queries that return a large number of items. Currently, the pagination limit is set to 1000 items per page.

query {
  networks(first: 1000) {
    # 1000 is the limit per connection
    edges {
      node {
        networkId
        assets(first: 1000) {
          # 1000 is the limit per connection
          edges {
            node {
              name
            }
          }
        }
      }
    }
  }
}

Although the pagination is within the limit, the query above will still fail because the complexity of the query is greater than the complexity limit which is more than 1000 x 1000 surpassing the 50,000 complexity limit.