Here a couple problems I've run into using GQL for backend to backend communication:
* Auth. Good GQL APIs think carefully about permission management on a per-field basis (bad GQL apis slap some auth on an entire query or type and call it a day). Back-end services, obviously, are not front end clients, and want auth that grants their service access to an entire query, object, or set of queries/mutations. This leads to tension, and (often) hacky workarounds, like back-end services pretending to be "admin users" to get the access they need to a GQL API.
* Nested federation. Federation is super powerful, and, to be fair, data loaders do a great job of solving the N+1 query problem when a query only has one "layer" of federation. But, IME, GQL routers are not smart enough to handle nested federation; ie querying for a list of object `A`s, then federating object `B` on to each `A`, then federating object `C` on to each `B`. The latency for these kinds of queries is, usually, absolutely terrible, and I'd rather make these kinds of queries over gRPC (eg hit one endpoint for all the As, then use the result to get all the Bs, then use all the Bs to get all the Cs)
gRPC is widely understood as an API tool for Microservices.
Microservices solve an organizational problem, not a technical one.
Ironically, gRPC doesn't really help to solve the organizational problem.
However, GraphQL in combination with Federation, also known as GraphQL Federation actually DOES help organizations to scale APIs across teams and services.
So, even though the typical popular opinion suggests that gRPC is better for Microservices than GraphQL, the reality looks different.
There were times when it was popular to generate a GraphQL API from your database but that's not how the query language is used today.
GraphQL is a query language to implement query style APIs.
These days, it's most widely used as a "Federation" layer to expose a single query-able graph on top of a (micro-) service architecture.
Here a couple problems I've run into using GQL for backend to backend communication:
* Auth. Good GQL APIs think carefully about permission management on a per-field basis (bad GQL apis slap some auth on an entire query or type and call it a day). Back-end services, obviously, are not front end clients, and want auth that grants their service access to an entire query, object, or set of queries/mutations. This leads to tension, and (often) hacky workarounds, like back-end services pretending to be "admin users" to get the access they need to a GQL API.
* Nested federation. Federation is super powerful, and, to be fair, data loaders do a great job of solving the N+1 query problem when a query only has one "layer" of federation. But, IME, GQL routers are not smart enough to handle nested federation; ie querying for a list of object `A`s, then federating object `B` on to each `A`, then federating object `C` on to each `B`. The latency for these kinds of queries is, usually, absolutely terrible, and I'd rather make these kinds of queries over gRPC (eg hit one endpoint for all the As, then use the result to get all the Bs, then use all the Bs to get all the Cs)