Cost Analysis
# When we have a public API we need to take care of:
Threat protection
Make sure that client ain't asking for too much response data. You can find an example of this here
Rate limiting
How many transactions per second per consumer are allowed for each endpoint.
Monetization
Charge customers based on the weight of their API call.
Potential Problem
In GraphQL our client can send a dramatically different kind of transactions. This means that for one query we might be able to process and return a response in less than a second but for another we might crash our entire backend due to workload volume!
[!CAUTION]
It is also possible that client might send a seemingly harmless not deep, not wide, not long query to our GraphQL service but in fact it is very expensive to run.
This brings us to the topic of this doc, we cannot treat all queries the same in GraphQL.
Solution: Calculating Queries’ Cost
By calculating each query’s cost we can:
- Prevent extremely heavy queries from being executed (DoS protection).
- Limit how many queries with a specific weight can be executed per second per consumer (rate limiting).
- And we can charge more for heavy queries compare to light weight queries (monetization).
Cost Analysis Methods
-
Static query analysis
We calculate potentially how heavy this query execution might be.
-
Dynamic query analysis
While the query is being executed on our server we calculate how heavy its execution was.
-
Query response analysis
Calculates query's cost based on the response.
[!NOTE]
Why we have three different kind of cost analysis?
Because we have 3 kind of need;
- We need to protect our GraphQL service from DoS attacks, thus we rely on how heavy one query might be.
- For rate limiting we can:
- Rely on dynamic query analysis and deduct after execution.
- Deduct first based on the upper bound and then refund if we’ve deducted too much.
- For monetization we can rely on dynamic query analysis.
- When I wrote this doc first I only watched one YouTube video and there he said that since scalar types are already presumably fetched from DB we’re gonna skip them from static query cost analysis. But there are other approaches to this too. Find out more here
Static Query Analysis
[!CAUTION]
It seems depth and complexity* are two different things when it comes to tooling. But in the grand scheme of things the complexity of a query increases with the number of fields AND the depth.
*Query complexity refers to the computational resources needed to fulfill a query.
Learn more about query depth limiting here.
- In NestJS we can do this in our complexity estimator function.
- E.g., assume we’re developing a GraphQL service for a bank and our client wanted to fetch the last 5 transactions of a user.
