Expand description
Compute, offline, the two numbers GitHub’s GraphQL API charges a query — the worst-case node count it may return and the rate-limit points one call of it spends — from the query text and its page-size variable bindings alone, before the query is ever sent.
§Two numbers, two limits
GitHub meters two different numbers against two different limits. Both are computed here, from one traversal of the document, and confusing them is the mistake this section exists to prevent.
| what it counts | what it is limited against | computed by | |
|---|---|---|---|
nodeCount | the maximum number of nodes one query may return | NODE_LIMIT, per query | node_count |
cost | the rate-limit points one call spends | an hourly budget, per credential, across everything that credential does | point_cost |
They are not two views of one quantity. A cheap query run in a loop exhausts
the hourly budget without ever approaching NODE_LIMIT; a single enormous
query is rejected outright while costing a handful of points. So a consumer
gating on one is not gating on the other, and the two are never renamed into
each other here.
§The rules, and where they come from
GitHub publishes both at https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api.
For the node count: it multiplies down a nested path, sums across
sibling paths, every connection supplies a first or a last inside
1..=100, and the limit one query may not reach is 500,000.
For the points: add up the number of requests needed to fulfil each unique connection in the call, assuming every request reaches its page-size limit; divide that aggregate by 100 and round to the nearest whole number; and never answer below GitHub’s stated minimum of 1. A connection is resolved once per parent node, so the requests it needs are the product of the page sizes strictly above it — which is the same quantity the node count multiplies by that connection’s own page size, and why one walk answers both.
Check this crate against that page rather than against our confidence.
§No schema, by design
node_count and point_cost are handed document text and nothing else.
They reach no network, read no credential, and consult no GraphQL schema — so
they cannot know which fields are connections by type. Instead:
- a field carrying a
first:or alast:argument is a connection: it multiplies the count beneath it, and it is one of the connections whose requests are aggregated; - every other field contributes no multiplier, no nodes and no requests of its own.
That is what makes this crate runnable in a fork pull request with no secret,
which is the whole reason a consumer can put it in a gate. The price is one
blind spot, stated plainly and applying to both answers: a connection
that supplies neither first nor last is invalid to GitHub and invisible
here. Such a field is treated as an ordinary field, so both the node count
and the point cost are an undercount rather than an error. A field supplying
both is also invalid to GitHub; the larger of the two is used, so both
answers stay a worst case.
§Example
use github_graphql_node_count::{
node_count, point_cost, NodeCountError, Variables, NODE_LIMIT,
};
let document = r#"
query($repos: Int!) {
viewer {
repositories(first: $repos) {
edges { node { name issues(first: 10) { edges { node { title } } } } }
}
}
}
"#;
let variables = Variables::from([("repos".to_string(), 50)]);
// 50 repositories + 50 x 10 issues.
assert_eq!(node_count(document, &variables)?, 550);
assert!(node_count(document, &variables)? < NODE_LIMIT);
// The same document against the other limit: `repositories` is resolved
// once and `issues` fifty times, so 51 requests round to one point.
assert_eq!(point_cost(document, &variables)?, 1);
// A page size GitHub would reject comes back as an error, not a number.
let over = Variables::from([("repos".to_string(), 500)]);
assert!(matches!(
node_count(document, &over),
Err(NodeCountError::PageSizeOutOfRange { .. })
));Structs§
- Position
- Where in the document a problem was found, rendered as
line:column.
Enums§
- Node
Count Error - Why a document’s node count could not be computed.
- Page
Size Argument - Which argument a connection took its page size from.
Constants§
- NODE_
LIMIT - GitHub’s published limit on the number of nodes one query may return.
Functions§
- node_
count - The worst-case number of nodes the one operation in
documentmay return, undervariables, computed by GitHub’s published rules. - point_
aggregate - The aggregate GitHub’s step 1 produces for one call of the one operation in
document, undervariables: the number of requests needed to fulfil every unique connection in the call, assuming each reaches its page-size limit. - point_
cost - The rate-limit points one call of the one operation in
documentspends, undervariables, computed by GitHub’s published rules.
Type Aliases§
- Variables
- The integer bound each page-size variable a document names is given, keyed by
variable name without the leading
$.