Query complexity calculations

Last updated

Query complexity calculation#

The Integration API calculates query complexity to prevent system abuse. The score is based on the number and type of requested fields and their associated costs. This complexity score helps enforce rate limits.

The algorithm is based on a GitHub document, with some modifications.

Details#

  1. Scalars usually don’t add any complexity score. Very few are marked as expensive, and then their score is 2.

  2. Objects add 1 + their fields' complexity. Only selected fields and their dependencies are taken into the calculation.

  3. Lists multiply the cost of a list item (object) by the limit. In case there’s no limit, a default of 10 is assumed for the sake of complexity calculation.

  4. Connections work like collections, but the limit is specified in either the first or last argument. In their structure, there’s a list of edges, which doesn’t add complexity points, as the multiplication happens on the connection level.

Simple example#

Let’s say we have a query like this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 { markets(limit: 50) { # 50 * (1 + 110) id name assignedToCountries(limit: 10) { # 10 * (1 + 10) code continent name states(limit: 10) { # 10 * 1 id } } } }

Up to 50 markets can be returned, each one with a list of countries (limited to 10), each potential country with up to 10 states.

Now, counting from the deepest level:

  • states will return up to 10 objects, each object is worth 1 complexity point, because they have only scalars inside;
  • assignedToCountries will return up to 10 countries, each country object worth 1 point for being an object, plus the child complexity of 10, for a total of 110 points.
  • markets will now be worth 1 + 110 per object, which multiplied by the limit makes a total of 5550 points.

More complex example#

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 { productVariantConnection(last: 100) { # 100 * (1 + 1 + 114) totalCount pageInfo { # 1 hasPreviousPage startCursor } edges { # no additional cost, it's part of the connection cursor node { # 1 + 3 + 110 id ...cost # 3 ...attributes @include(if: true) # 110 } } } } fragment cost on ProductVariant { unitCost { # 1 + 1 + 1 currency { # 1 code } formattedValue converted { # 1 formattedValue } conversionDate conversionRate } } fragment attributes on ObjectWithAttributes { attributes { # 10 * (1 + 10) description ... on MappedAttribute { id } elements { # 10 key description ... on AttributeStringElement { value } } } }

Now the calculations starting from the fragments:

  • The cost fragment consists of one object with another two objects nested in it, so its complexity score is 3.
  • The attributes fragment returns a list with a list embedded in it. Since there are no limit arguments, a default value of 10 is taken on both levels, so it makes a total of 110.
  • Each ProductVariant object is now worth 114 complexity points, edges list doesn't add complexity, and pageInfo adds only 1. Multiplied by the limit from the last argument (100), the total complexity becomes 11600.

Expensive scalar example#

1 2 3 4 5 6 7 { categories(limit: 100) { # 100 * (1 + 2) id name displaySortType # expensive = 2 } }

Here the displaySortType is marked as "expensive", because it has a complex formula. Other than that, the calculation is pretty basic: each category object gets a score of 1 + 2, and there are up to 100 categories returned, for a total of 300.

Individual query complexity limit#

The maximum complexity of any individual query to the Integration API is also limited, and the limit is 100 000 complexity points.