Skip to content

Apollo Federation Compatibility #528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
maryelizbeth opened this issue Jul 29, 2022 · 14 comments · Fixed by #603
Closed

Apollo Federation Compatibility #528

maryelizbeth opened this issue Jul 29, 2022 · 14 comments · Fixed by #603
Assignees

Comments

@maryelizbeth
Copy link

Hi Y’all,

Super excited to see that 1.4.0 included support for Apollo Federation.

Our team at Apollo maintains the Apollo Federation Subgraph Compatibility repo. Our goal for this project is to highlight projects that have support for Apollo Federation so that users of those libraries can see a visual representation of that support. We also include libraries in this list within our test suite to further validate their functionality.

If you’d like to have your project tested against the Apollo Federation spec and displayed within this list, you can take a look at getting started here, or open an issue on our repo.

Our team is happy to help with the process and answer any questions! Let me know what y’all think.

@dariuszkuc
Copy link

Hello 👋
We (Apollo) are working on growing the Apollo Federation support in the Open Source ecosystem. As Mary mentioned above our Apollo Federation Subgraph Compatibility repo highlights projects that support Federation. graph-gophers/graphql-go is a great library and we would love to see example integration included in the repo as well.

Based on my cursory glance, it appears that this library currently has very limited Federation support (i.e. just supports _service { sdl } query). Are there any plans on better Federation support? Is there any way we can help out with building out the support in graph-gophers/graphql-go?

I recently introduced Federation support to graphql-go/graphql* (see https://github.com/dariuszkuc/graphql/tree/federation/federation) and I believe something similar (i.e. new federation module) could be introduced to this repo as well. Since we have access to the AST (and directives) I believe the PR should be rather straightforward and we may not need any additional changes to the core library. Would you be interested in accepting a PR with this functionality?

*PRs are still open and pending

@dariuszkuc
Copy link

Hello 👋
@tonyghita @pavelnikolov @nicksrandall - any thoughts on this? Would you accept a PR with new federation package?

@pavelnikolov
Copy link
Member

pavelnikolov commented Nov 10, 2022

Hi @dariuszkuc and @maryelizbeth

Thank you for the interest. PRs would be considered and accepted as long as they do not introduce backwards compatibility and do not increase significantly the complexity of the library. I'd be happy to discuss any potential changes required.
@dariuszkuc what would be the required high level changes to the API of the library? How would these affected existing users? Would such a feature be opt-in?

I'm more interested to know which features of the GraphQL spec are missing in this library that would prevent you to consume schemas from this library from Apollo. The way I see it there are two sides to this issue:

  1. allow Apollo Graph Router to use servers built using this lib as a subgraph; and
  2. implementing the federation itself, allowing servers built using this app to be the federating server.

Am I understanding this correctly?
What are the missing features in this lib that would prevent us from implementing 1)?
Do we even want to implement 2? Is it possible to make this library extendable so that users would be able to implement federation without having federation built in?

@dariuszkuc
Copy link

Hello 👋

I was hoping we could create new federation package within this repository that would expose ParseFederatedSchema/MustParseFederatedSchema functions in a similar way as the main graphql package. Ideally new package would be just a wrapper on top of the core lib and those functions would delegate the calls to the ParseSchema/MustParseSchema and then modify the returned schema objects with additional Federation info. By having the package living in the same repository it would make it much easier to discover and ensure that it is always compatible with the latest library changes.

The way I see it there are two sides to this issue:

  1. allow Apollo Graph Router to use servers built using this lib as a subgraph; and
  2. implementing the federation itself, allowing servers built using this app to be the federating server.

IMHO without having the library support (# 2), users writing their GraphQL servers (# 1) have to keep re-implementing it (# 2) themselves.

In order to create Apollo Federation compatible subgraphs we need to make few schema modifications:

  • have ability to specify federation directives
    • ideally lib would add federated directive definitions so they could be skipped from the .graphql schema files and users just specify @link directive on the schema definition/extension and everything else is imported automatically - I believe we could do it through the exposed ASTSchema
  • library has to be able to find reusable/referenceable types AKA entities (types that specify @key directive)
    • since graphql.Schema exposes ASTSchema we should be able to iterate over the types and find the ones with @key directive
  • create new _Entity union type of all entities and corresponding _entities(representations: [_Any!]!): [_Entity]! query
    • we should be able to add both to the ASTSchema
    • unsure - how do we specify the _Entity union type/_entities field resolvers?
      • guess users could specify those two resolvers in the passed resolver interface{} but just wondering whether the API could be more explicit
  • create new _Service { sdl } type and corresponding _service: _Service query

Based on my brief exploration, I don't think there would be any changes to the core lib and fed support could be provided through a new package (see above). Guess if we would like to keep Query type "clean", then maybe we could find a way to define _entities as a meta field similar to _service (IMHO those two fields should only be available if users explicitly opt-in to federation by using the schema builder from the new package).

@pavelnikolov
Copy link
Member

@dariuszkuc thank you for putting down your thoughts. Do you think such a package would require any additional dependencies? Ideally, I do not want to add dependencies to the library. I like the idea of making the _service and _entities opt in only if you use federation through that special package.

@dariuszkuc
Copy link

dariuszkuc commented Jan 13, 2023

Hello 👋
I don't think federation package would need any additional dependencies.

Apologies but I didn't get a chance yet to work on this. Creating new federation package should be simpler now as well, I just externalized our fed compatibility test suite (blog post coming soon) so library authors can run tests before adding integration to our testing repository. Integration tests can now be run using executable NPM script and Github Action.

@steve-gray
Copy link
Contributor

Is there any roadmap or plans to support a more meaningful set of features for Apollo Federation in the near term? Having just started decomposing a large graphql-go application, we were pretty gutted to find things just didn't work as we hoped.

@pavelnikolov
Copy link
Member

@steve-gray The goal of this library is to support the official GraphQL spec. Apollo Federation is not in the short-term roadmap. With that being said, PRs extending the library and covering any missing pieces from the official GraphQL spec are more than welcome. If a feature can be added in an opt-in way without changing the core of the library then it would be considered.

@pavelnikolov
Copy link
Member

pavelnikolov commented Feb 2, 2023

Just for the sake of clarity, the problem I have with adding Apollo Federation support in this library is that it is not in the official GraphQL spec. And if it is not in the official GraphQL spec it might change in future. I'd be more than happy to consider adding missing pieces of the puzzle (from the official spec) that would allow users of this library to implement Apollo Federation themselves. There has been Apollo schema stiching, then federation v1 and now federation v2. Once federation is considered stable and accepted in the official GraphQL spec, then I'd reconsider adding it to the core of this library. I'm not afraid of joining late to the party, however, I'm definitely afraid of joining too early. In the mean time any ideas, improvements or PRs are welcome.
Our current efforts are to add custom directives (at least on FIELD_DEFINITION) in the next release. Let me know what other changes would be required in order to implement the subgraph compatibility spec?

@steve-gray
Copy link
Contributor

The main areas would be:

  • Annotations support
  • Entity resolvers to look up objects by @key variants
  • Ability to reference objects that don't exist locally with the extend keyword.

That would at least in principal allow the package to be used with an external federation router that handles the supergraph and cross graph joining.

@pavelnikolov
Copy link
Member

pavelnikolov commented Feb 25, 2023

This weekend I decided to actually learn more about Apollo Federation and try to run the full Apollo Federation Subgraph using this library. So far it is (almost) working, however, there is one small issue remaining. This library requires Go fields/methods corresponding to a GraphQL field to be exported (public fields). This means that if I have a func like:

func (r *QueryResolver) _Entities(ctx context.Context, args struct{ Representations []Any }) ([]entityResolver, error) {
    // ... resolver here
}

it wouldn't work because the above func is private in the Go world since it doesn't start with a capital letter.

Of course, I can add a schema option which adds this resolver field, however, I want to resolve this in a way that would make the library compatible with the latest GraphQL spec and allow users to define resolver fields with leading _, which is perfectly valid according to the spec.
I am considering a few solutions. One of them is introducing a graphql reflection tag, which would allow users to override the name, e.g.:

type queryResolver struct {
    Entities func(ctx context.Context, args struct{ Representations []Any}) ([]entitiesResolver, error) `graphql:"_entities"`
}

Note the graphql:"_entities" at the end of the field definition. This would instruct the library to match that struct field to the _entities field in the GraphQL query. I'll think a little bit more on this. However, I just wanted to let you know that this is the last thing that prevents this library from fully supporting the Apollo Federation Subgraph spec (without actually knowing anything about federation or Apollo at all).

cc @steve-gray @dariuszkuc @maryelizbeth

@pavelnikolov
Copy link
Member

pavelnikolov commented Feb 25, 2023

While trying the above I fixed two bugs in the library to make it compatible with the latest stable spec. So thank you for raising this.
I'll raise a PR with my example when I fix the leading _ in names. I just raised an issue about that: #593

@dariuszkuc
Copy link

Thanks for the update. Awesome progress!

@pavelnikolov
Copy link
Member

@dariuszkuc @steve-gray @maryelizbeth
I merged #603 in the master branch and it adds an example subgraph. Could you, please, help me verify it would be enough to satisfy all the requirements of the subgraph spec. I would appreciate some help to create a realistic example of two subgraphs which get used by a gateway. This example is in the master branch but it hasn't been released yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants