Skip to content
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

feat: Support Federation v2 #196

Merged
merged 19 commits into from
Jun 21, 2022
Merged

feat: Support Federation v2 #196

merged 19 commits into from
Jun 21, 2022

Conversation

col
Copy link
Contributor

@col col commented Apr 27, 2022

This PR adds support for the @sharable, @inaccessible and @OverRide directives. I believe this is all that is required to support Apollo Federation v2.0.

Issue: #153

Original PR #195 was closed due to branch rename.

@rmosolgo
Copy link

👍 Seems like it should do the job! The only new feature I read about but didn't see in the tests was @key(..., resolvable: false), but it looks like the existing add_directive(...) method should cover it.

@daemonsy
Copy link
Contributor

daemonsy commented May 4, 2022

Hey @col thanks for submitting this. 👏. I personally haven't caught up with the changes in Federation V2. We should be able to put some focus on this in mid month.

Meanwhile, @lennyburdette if you're around, be nice to get some thoughts from you on this PR.

@lennyburdette
Copy link
Contributor

lennyburdette commented May 4, 2022

This is great, thanks for putting this together!

I'd like to make one suggestion: can there be a way to explicitly opt-in to Federation 2 (so that it adds the @link directive) without using one of the federation 2 directives? (shareable, inaccessible, override). Maybe federation_version: 2 in the GraphQLSchema subclass?

A common workflow for converting a subgraph to Federation 2 looks like this:

  1. Add the @link directive to opt into new Federation features.
  2. Run composition (either rover supergraph compose or rover subgraph check).
  3. Use the composition errors and hints to figure out which fields need to marked as @shareable.

The rules around shareable types and fields and the @shareable directive don't come into play until you opt into Federation 2 with @link. It can be difficult to tell which fields need to be marked shareable, and we'd prefer people let the composer dictate that rather than having to guess (and probably mark too many fields as shareable!)

Otherwise, I think the code is sound and I'm excited to see this land!

col added 2 commits May 5, 2022 09:18
This is more explicit and extendable in the future if we ever need any other federation options at the schema level
@col
Copy link
Contributor Author

col commented May 5, 2022

Good suggestion @lennyburdette! I was never very happy with my initial approach of searching for usages of the v2 directives.

I've opted for the version to be a keyword arg so that we can add other options in the future if required.
Example:

class MySchema
  include ApolloFederation::Schema
  federation version: 2
end

Copy link

@lyricsboy lyricsboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to seeing this land!

FEDERATION_2_PREFIX = <<~SCHEMA
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@extends", "@external", "@requires", "@provides", "@shareable", "@inaccessible", "@override"])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's importing all of the directives unconditionally. Is that acceptable, or should it be more dynamic to only import the directives that are actually used in the schema?

Apollo docs say "Modify the import array to include whichever federated directives your subgraph schema uses."

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is @extends a valid directive in this context? I don't see it in the docs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One subtle feature of the @link spec is that you don't have to import these directives. If you don't supply the import: argument, the directives are still available in a namespaced form:

extend schema @link(url: "https://specs.apollo.dev/federation/v2.0")

type Foo @federation__key(fields: "bar") @federation__shareable {
  bar: ID!
  baz: String @federation__external
  quux: String @federation__requires(fields: "bax")
  blah: String @federation__inaccesible
}

This might be the "right" approach for a code-first library. The key ruby method could output @federation__key.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yes, I believe the @extends directive was dropped entirely in Fed 2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @extends is still optionally supported. We either need to support @extends or have proper support for type extensions (eg. extend type).
See: https://www.apollographql.com/docs/federation/federation-spec/#federation-schema-specification

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have an example problem scenario, no. I honestly don't know what impact importing all of the directives might have. I suppose there's a possibility that a Graph has already defined directives with the same names, and those could be in conflict with the Apollo Federation directives -- thus an author might need to use the namespaced directives to work around that. Is that a realistic scenario?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs for the @link directive cover the namespacing feature, which is actually configurable using as:. I'm inclined to agree with @lennyburdette on the preference to use the namespaced directives in this implementation, and thus avoid the need to specify the directives in the @link declaration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out the spec—that's exactly where the import: behavior is documented. Here's what the federation team says about using import or not:

you can absolutely skip any import and use @federation__key and I can see many code-first libraries doing just that since it’s probably a bit simpler (no worries about name conflicts, etc…).
...
if it matters to you that the SDL you generate is as readable as possible, then using the import makes sense.

The only benefit to not using import and emitting the namespaced directives is that it would allow graph authors to use the shorter directive names for their own purposes. But you could also support that with a DSL for emitting import: [{ name: "@tag", as: "@mytag" }] so you're not painted into a corner if you choose the short names today.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is done currently, @lennyburdette , does it pass the @link test in https://www.apollographql.com/docs/federation/other-servers/?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this should be sufficient. The test is rudimentary right now: it just searches the _Service.sdl for the presence of "@link": https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/main/src/tests/link.test.ts

@daemonsy
Copy link
Contributor

daemonsy commented May 20, 2022

Hi @col @lyricsboy @lennyburdette thanks for all the work and comments on the PR so far.

@geshwho and I paired over reviewing the 2.0 spec and the PR. Overall the PR looks great! Jotting down a few notes:

Code considerations

Proposed ops for shipping

  • When reviews are all good, we will ship this a major version bump (technically it's non breaking)
  • Help internal Gusto apps adopt the latest gem version whilst still using V1. This helps to ensure that we didn't break anything in V1 backwards compatibility. FYI @grxy we can discuss separately switching to V2.
  • Mark on the README that beta 2.0 support is available, encourage folks to try it out.
  • Remove beta when we're confident. Ideally, by that time, Gusto is already on V2.

Copy link
Contributor

@daemonsy daemonsy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thanks for adding 2.0 support to the library. Just some general code comments in this review.

I'll take the feature branch out for a spin with our main app later today.

spec/apollo-federation/service_field_spec.rb Outdated Show resolved Hide resolved
README.md Outdated
```ruby
class MySchema < GraphQL::Schema
include ApolloFederation::Schema
federation version: 2.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might this be the place to support import?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version: should probably be a string. we don't foresee a need for 2.0.1 but it's possible

FEDERATION_2_PREFIX = <<~SCHEMA
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@extends", "@external", "@requires", "@provides", "@shareable", "@inaccessible", "@override"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is done currently, @lennyburdette , does it pass the @link test in https://www.apollographql.com/docs/federation/other-servers/?

@lennyburdette
Copy link
Contributor

FYI I spoke with the maintainer of graphql-kotlin (another code-first graphql library) and I think we're settled on emitting only namespaced directives (@federation__key) and not providing an API to specify imports or renames. I'm pretty sure this will be the path forward for most code-first libraries.

@daemonsy
Copy link
Contributor

Thanks @lennyburdette !

@daemonsy
Copy link
Contributor

daemonsy commented Jun 2, 2022

Hi @col are you still actively working on this PR? No worries if you're not able to, we can merge the existing work and do some of the action items separately.

@col
Copy link
Contributor Author

col commented Jun 7, 2022

Hi @col are you still actively working on this PR? No worries if you're not able to, we can merge the existing work and do some of the action items separately.

I'm happy to incorporate some of the feedback and update the PR over the next day or two.

This approach feel a little easier to understand
@col
Copy link
Contributor Author

col commented Jun 7, 2022

@daemonsy (CC: @lennyburdette @lyricsboy) I've updated the PR with your feedback. Please take another look.

Changes:

  • Changed the federation version to support semantic versioning
  • Remove the explicit import of the federation directives
  • Output the directives using the federation__ namespace prefix when using >= 2.0
  • Split the service field specs into v1 and v2

@daemonsy
Copy link
Contributor

daemonsy commented Jun 8, 2022

Hey @col it's looking good to me. I am going to run some sanity check on the PR using our codebase.

@lennyburdette how does it look to you?

@lennyburdette
Copy link
Contributor

looks great!

Copy link

@sethc2 sethc2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Just a couple grammar nits.

Thanks for putting this together!

spec/apollo-federation/schema_spec.rb Outdated Show resolved Hide resolved
spec/apollo-federation/schema_spec.rb Outdated Show resolved Hide resolved
@pmrotule
Copy link

@daemonsy Any update? Can't wait to use this feature 😅 👏

@daemonsy daemonsy changed the title Support Federation v2 feat: Support Federation v2 Jun 21, 2022
@daemonsy daemonsy merged commit 238736c into Gusto:main Jun 21, 2022
@daemonsy
Copy link
Contributor

Thanks for working on this @col and your patience in getting the PR through 👏

@rylanc
Copy link
Contributor

rylanc commented Jun 21, 2022

🎉 This PR is included in version 3.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Successfully merging this pull request may close these issues.

8 participants