My REST endpoints allow a `fields` parameter that specifies the requested fields of the endpoint. Even if you do have a huge object, you can pare it down. To get only `id` and `first_name` on a `User` endpoint, you do `.../rest/User/fields={"id"=true,"first_name"=true}` . Non-standard, but effective. The backend doesn't retrieve or send the un-needed fields.
And you can extend this pattern it by allowing "includes" which would signal to the backend to load and deliver the relations listed in the includes part of the query.
This alone makes it impossible to get backend to return god entities with dozens of relations without explicitly specifying them.
My system has its limitations however. It can't do relational constraints like GraphQL or renaming of fields, but it is likely the 20% that gets you 80% of the way.
To be honest, once you can traverse relationships like this, you've basically just got GraphQL in disguise and might as well be using it. You're going to have all the same difficulties as GraphQL in making it perform well, but don't have the elegant (IMO) query language -- and lose some of the expressivity of fields/relations being able to accept arguments.
Except I dont have to start with GraphQL. I can add the complexity when I need it instead of starting with complexity. Yes I finally got _one_ of the features of GraphQL, but I didn't have to swallow graphql or require everyone else to. They don't have to use the field specifier and it still looks very simple. In contrast to GraphQL.