So far so good, especially on the front-end. We love the queries, the caching downside don't bother us too much, but mutations make me a little nervous (conceptually, ecumenically, grammatically...).

On the server side, it is a mixed bag. Defining a new type system on top of our existing one, and on top of the Avro schemas we have for inter-service communication, it feels... a bit much. Each layer has a purpose so I can't advocate for removal, but it does feel silly at times. Also the documentation on pagination feels incomplete to the point of confusion, and depending on how you search for answers, you might find blog posts that add confusion rather than clarity.

Some additional friction came from the specific version of the Ruby server library we jumped in at. They went a little overboard in the amount of metaprogramming used by the DSL, and I say that as someone who enjoys metaprogramming shenanigans for fun on a Friday night! But it took a long time to understand why adding some custom behavior, in a way that seemed utterly necessary, was not possible (e.g. defining methods inside the DSL's type block did not class_exec them into existence on the resulting class in any reasonable way). They have since released a new version whose main API is class-based, which is much more clear, enables everything I desire, and I am eagerly awaiting next month when we get to upgrade to that and refactor. Thanks to the maintainers for recognizing this was needed, and for doing the heavy lifting to pull it off!

What I enjoy about GraphQL conceptually is that it dodges a certain square-peg-round-hole issue I occasionally saw with REST, but in the same way that leaves me nervous that we'll end up back at a land of inconsistent RPC spaghetti. In an API where an iron-fisted "RESTful Actions Only!" rule is enforced, many domains find just those one or two actions that feel like they are a better fit for their own unique verb, a custom-named action. The rhetorical-and-ontological escape hatch for REST's limited verb set is to have an abstract "resource" that only has, say, a POST option. You can only "create" an "/recalculate_contacts" resource, but never GET, DELETE and so forth. Or you PUT to "/contacts/recalculate", or some other silliness that just feels too clever by half.

Those of us who were scarred by inconsistent, poorly-thought-out RPC spaghetti over the years cling to REST because it brought peace to our nightmares via simple rules that almost fit everything, and as a bonus, really gel with HTTP semantics. Because GraphQL's Mutations really don't specify much of anything, I immediately assumed it would descend into a sort of API moral decadence, but that has not borne out so far.

If anything, I am heartened to see that newer (though not necessarily younger!) developers, who grew up in a world where REST was all they knew, do not have this temptation to go off the deep end with action names, or to craft RPC-esque systems with ill-considered boundaries of behavior. For the most part they want to name things ala REST, because that's what they are used to, except once in a while. So that is what our company goes with in terms of mutations: Wherever possible, name it for the CRUD action it represents. Only use a more unique/one-off verb if it is truly justified.