This is actually solvable. The queries that will be executed by an app can be analysed statically, and therefore are available as part of a build pipeline. So it's possible to create a whitelist of queries automatically, or even go one step further and give each query a short unique ID and just say "execute query foo with these parameters" rather than sending the actual body of the query over the network.
When a solution requires this kind of hacks for a simple task as rate limiting, maybe the solution is a bad one to begin with.
With REST it is fairly easy to do rate limiting on endpoints.
With GraphQL, it is fairly easy to DDOS with a complex query that will ask the server to fetch an insanely complex data structure. And there are no endpoints anymore.