GraphQL connectors? (Yes, GraphQL, not REST)

HI! I’m going to be fishing for opinions here/experiences here, both from you with actual experience and those who are yet contemplating it.

Apollo Federation does great things for GraphQL but GraphQL itself has edges that are sharp and prickly (pun fully intended). I’ll mention just two - namespacing, but there are numerous others (read this proposal of mine if you’re interested).

Now, while I would very much like to get that proposal going faster, it can’t happen immediately and can’t change the past or some other things. We’re at the stage where we:

  1. May already have legacy GraphQL services that aren’t federation-ready in structure/model and not just directives.
  2. May want to expose additional or different models (schemas) to specific clients beyond just filtering them down.
  3. We had our fun with the federation, learned some lessons, and now want to do a better job while retaining the compatibility with existing federation clients and would appreciate help in that respect.

Now, what I’ve done in the past is to perform model/graph transformations at run-time to present a GraphQL schema that appears different from what it is backed by, back in ~2021. Now, that specific case wasn’t federated but the principles are the same and, at least analogous. What I had to do, in order of increasing complexity:

  1. Rename types to make them more publicly appropriate. This can also be useful for shoehorning namespacing.
  2. Remap values - you can easily see how this can work for enums but it also applies to representation forms of other types - dates and timestamps are easy examples, blank strings and magic values misused in place of nulls, but there are many others.
  3. Transform raw ids into links and, perhaps, hide those raw ids.
  4. Add extra documentation and directives not present in the source (think sample/test data, requests, ownership, etc)
  5. Change link cardinality between “…-to-one” and “…-to-many” to align with the future direction. Yes, …to-many can change to …-to-one if it never had more than one value.
  6. Introduce link shortcuts - these can either expose a longer chain as a single link or apply criteria to match specific values from -to-many mixed bags or a combination of those.
  7. Rework edge case and error handling, convert/move between in-data embedded errors and GraphQL errors.
  8. Much of the above on the input/argument side, in the other direction. This gets especially tricky when trying to present a common approach to expressing search criteria across otherwise varied subgraphs.

There are few extra things of interest here:

  • This could be done as a wrapper, too.
  • It would be nice to be able to run this outside federation too, to test a subgraph in isolation
  • This could be used in front of Federation, as a part of the “Contracts” feature too, to add extra power there.
  • It could support AOP cross-cutting so that repeated transformational patterns don’t need to be explicitly duplicated and reduplicated, many times (pun intended, again).
  • Depending on how it is done, it may form a “core” that could be applied to other connectors, such as REST but also others.

How many of you would consider this helpful, either to continue your federation journey or to eliminate fears of starting one?

I’d be, given time to dedicate to this, very interested in working on the above. Anyone else? Apollo?

1 Like

Here’s a related thread - REST Connectors to call other GraphQL APIs? … using the REST connectors to call a graph API

1 Like

Yeah, I’m aware of that but I’m trying to gauge if there is interest for more than that, with more comprehensive runtime model transformation as described.

Great question, and an interesting topic that has also come up on my teams recently, specifically the namespacing topic.

For my context, we had a subgraph team that wanted to use a generic term (“Step”) for a specific domain context in the supergraph that would only ever be used for a specific execution step in their async pipeline. I recommended a prefixed version of this since they didn’t intend to make this a common shareable type amongst multiple subgraphs. The conversation very quickly turned into “I wish graphql had namespacing.”

The arguments for not having the prefix was that it made all of the generated class names long, and that it made attempting to read the schema appear long as well since all of their domain specific objects were prefixed with their domain.

The arguments for the prefix was that it made browsing the schema much easier, specifically looking at the apollo docs when searching for objects. A counter argument for the reading of the schema was also made due to the field names being more important and more often used than the type names, and that the type names are not often used in queries except for the ... on syntax, or in interfaces and unions.

Ultimately, I think I personally land on prefixing types that aren’t intended to be shared a good practice, and the need for namespacing is an anti-pattern. I have a blog idea that maybe one day I can finalize (I have an AI draft of my ideas), but here is the AI generated summary of it:

In a federated GraphQL schema, type names must include relevant context to prevent ambiguity and conflicts, making built-in namespacing unnecessary and even harmful. Namespaces encourage artificial separation, creating unnecessary indirection and making schemas harder to navigate. Descriptive type names provide immediate clarity, prevent unintended reuse, and ensure that each domain owns its types explicitly. Attempts to enforce generic, reusable types often lead to tight coupling and maintenance headaches. While some argue namespaces would simplify schema design, they would instead obscure intent and introduce unnecessary complexity. Explicit, context-rich type names are the best way to maintain a scalable and understandable GraphQL schema without relying on restrictive namespacing constructs.

The general idea is that things that overlap on naming that are distinct should have distinct names with the context in the name. Things that overlap on naming that are generic should be generic enough to handle the scenarios of each party attempting to use the name.

The eight things you have listed you have done can in my eyes be simply boiled down to a single statement: good schema design. The biggest problem I have seen is that schema design is not an intentional effort up front, so people see those eight things you have done as problems that needed to be solved after build, but each one of those things really could have been product requirements that should have gone into a design before building, especially if they change the user’s experience.

The 8th item you listed is particularly interesting (Much of the above on the input/argument side, in the other direction.). This is where I think people get tripped up with GraphQL the most. In my team, this is where I need to get people to stop thinking about “endpoint response” in terms of REST, and start thinking about “navigating the graph.” This really just boils down to how the data canonically relates to each other, and then writing the resolvers to support that such that it works circularly. Part of my 2024 Summit Talk was about this, but I realize I should have gone more in depth about how to handle navigating both directions. The relevant section would be about making sure that singular object fields do not require context of other objects so that you can avoid “from the perspective of [ X ]” type fields, and those should instead move to an edge or some other intermediary object. The resolvers themselves are tricky for this as they pretty much require that they are done with field level resolvers.