Limits and errors
Depth limit
Section titled “Depth limit”A query nested more deeply than the depth limit is rejected before it runs. The limit is a server setting, 10 levels by default at this build. The published queries never need that much nesting.
Cost limit
Section titled “Cost limit”Every query is given a cost before it runs. If the cost is over the maximum, the query is rejected and nothing is executed.
How the cost is worked out:
- Each field you select costs 1.
ordersandproductscost 5 each.__typenameis free. - A field that takes
first(orlast) multiplies its own cost, plus the cost of everything selected under it, by the number you ask for. - If you pass
firstas a variable, the variable’s value is used. If the server can’t read it as a whole number, it assumes 20. - At this build,
limitarguments (onconsignments,consignmentInvoices,retailerStatementsandretailerPayments) do not multiply the cost.
Worked example:
query RecentOrders { orders(first: 50) { edges { node { number status grandTotal { paise } } } pageInfo { hasNextPage endCursor } }}| Part | Cost |
|---|---|
grandTotal { paise } |
1 + 1 = 2 |
node { number status grandTotal {…} } |
1 + (1 + 1 + 2) = 5 |
edges { node {…} } |
1 + 5 = 6 |
pageInfo { hasNextPage endCursor } |
1 + 2 = 3 |
orders(first: 50) {…} |
(5 + 6 + 3) × 50 = 700 |
The maximum is a server setting. Its default at this build is 5,000. Read the limit in force from the error rather than hard-coding it.
Example (with the default maximum):
{ "data": null, "errors": [ { "message": "Query cost 7000 exceeds the maximum allowed cost 5000. Request fewer fields or smaller pages.", "extensions": { "code": "QUERY_COST_TOO_HIGH", "cost": 7000, "maxCost": 5000 } } ]}If you hit it, select fewer fields or ask for smaller pages.
Introspection is off
Section titled “Introspection is off”Schema introspection (__schema, __type) is turned off in production. Whether it is on is a server setting; this is the behaviour observed on the production API. A query such as { __schema { queryType { name } } } is rejected with:
GraphQL introspection has been disabled, but the requested query contained the field '__schema'.Use the API reference on this site instead. It is generated from the production schema.
Error messages are masked
Section titled “Error messages are masked”In production, unexpected errors are replaced with the message Unexpected error. and carry no extensions. Permission errors and query validation errors keep their real messages. This is the observed production behaviour; for example, a malformed cursor on products returns:
{ "data": null, "errors": [ { "message": "Unexpected error.", "locations": [{ "line": 1, "column": 3 }], "path": ["products"] } ]}Inputs that are not valid also end up as Unexpected error., for example:
- a malformed cursor in
after, - a negative
first, - a malformed ID, such as a
dealerIdthat is not a validDealerID.
Check your inputs before you report one of these to your RaviFurnitures contact. Include the time of the request when you do.
The shape of errors
Section titled “The shape of errors”A request that reaches the API returns JSON. Errors are listed in the top-level errors array. Check that array; don’t rely on the HTTP status alone.
{ "data": { "order": null }, "errors": [ { "message": "You do not have access to this order.", "locations": [{ "line": 1, "column": 3 }], "path": ["order"], "extensions": { "code": "PERMISSION_DENIED" } } ]}extensions.code |
Meaning |
|---|---|
PERMISSION_DENIED |
No usable key, or the key lacks a permission. See Authentication. |
QUERY_COST_TOO_HIGH |
The query is over the cost limit. |
| none | Validation errors (unknown field, wrong argument type) and masked errors. |
A field that fails is returned as null. All published queries except order and product return a non-null list or page, so an error in one of them makes the whole data value null. If you ask for several top-level fields in one request, one failure can blank the others: keep each request to one top-level query.
Some unpublished operations report business errors in an errors list inside their own result (with field, code and message). The published queries don’t: their errors are only in the top-level errors array.
Pagination
Section titled “Pagination”The published queries page in two different ways.
Connections: first and after
Section titled “Connections: first and after”Used by orders, refunds and products.
first: how many items. Default 20, maximum 100. Larger values are reduced to 100 without an error.after: theendCursorfrom the previous page.pageInfo { hasNextPage endCursor }tells you whether to continue.totalCountgives the total.ordersandrefundscome newest first.productscomes newest first unless you passsortByorfilter.search(a search orders by relevance).
query OrdersPage($after: String) { orders(first: 100, after: $after) { totalCount edges { node { number } } pageInfo { hasNextPage endCursor } }}A cursor marks a position in the list, not a record. If new records arrive while you page through, the list shifts and you may see an item twice. If records are removed, you may miss one. Always upsert by a stable key (order number, product slug) and repeat full sweeps from time to time.
Lists: limit and offset
Section titled “Lists: limit and offset”Used by consignments, consignmentInvoices, retailerStatements and retailerPayments.
limit: default 50. The maximum is 100 forconsignmentsand 200 for the other three. Larger values are reduced without an error.offset: how many records to skip.- Results come newest first. A page shorter than your
limitor the cap, whichever is smaller, is the last one.
The same shifting applies when records are added during paging.
Full lists
Section titled “Full lists”warehouses and lowStock return everything in one list.
Rate limits and timeouts
Section titled “Rate limits and timeouts”The application applies no per-key or per-IP rate limit to the published queries at this build. Limits outside the application are not described here. Either way, don’t poll hard: run one sync worker per integration, and wait and retry with growing delays when requests fail.
Very large queries can run into server time limits and fail with Unexpected error.. Keep pages small.