Gqlgen: Support for Apollo Federation

Created on 12 Jun 2019  路  44Comments  路  Source: 99designs/gqlgen

Are there any plans to add this functionality to GQLGen?

accepted enhancement

Most helpful comment

@marwan-at-work has started looking at this

All 44 comments

@marwan-at-work has started looking at this

@marwan-at-work Let me know if I can do anything to help you, like testing etc.

Ref: #5

BTW, If you are looking for a golang graphql which composes the overall schema and executes federated queries, consider nautilus gateway as a starting point. It does not currently implement the Apollo Spec, but does provide federated graphql gateway functionality.

We (Khan Academy) are also interested in this -- @marwan-at-work if there's anything we can do to help (either writing code or testing/etc.) let me know (here or benkraft at khanacademy dot org)! I have some time allocated this month to work on federation backend support and we're very keen to start using it as soon as possible!

Is there any progress here? I'm in dire need of this feature and I'd be happy to help in any way that's required / useful.

@BitPhinix I've gotten a little busy at work but I'm back working on it. The @key is working as intended for MVP in my branch above. The @requires will change the signatures and that's what im working on now

If you are not using any of the new directives (ie, just want apollo-gateway to connect to your graphql service) possibly because you are only running one graphql service currently or just testing things out, you can get a little bit done by just copying the graphql schema in https://www.apollographql.com/docs/apollo-server/federation/federation-spec/ and put it into your own schema (you'll need to manually return a sdl string that constitutes your schema as a whole). And then the gateway is able to connect to the gql server just fine and act as a pass through.

as a matter of fact, if you're not using any of the new directives, all you need to include in your schema is the _sdl that returns the string representation of your graphql.schema file, and you're federation-ready.

But if you start to need the directives, you can always implement them yourself as part of your business logic.

This issue is more about creating an abstraction layer that separates the Federation Spec details from the business logic.

Here's the super preliminary initial support for @requires https://github.com/marwan-at-work/gqlgen/commit/2800f1d15e942fb019c1a6cce249204edd230707

Note that gqlgen creates directives on any field as a middleware layer, which seems unnecessary for @external and I'll need to look into how we can make the generator ignore certain directives.

Most of the kinks in @requires has been fixed including correct type unmarshaling and removing the directives from the middleware as mentioned above.

I've forked the Apollo federation-demo and ported all the services into Go which you can try here: https://github.com/marwan-at-work/federation-demo

Definitely let me know if anything seems off or wrong

:v:

@marwan-at-work is there an idea of having the gateway generated in gqlgen as well? perhaps as a plugin?

~@marwan-at-work we'd love to try out the new mvp code. Is there a way to easily pull it in via go modules?~ n/m I found it in your federation-demo, add this to our go.mod:

replace github.com/99designs/gqlgen => github.com/marwan-at-work/gqlgen v0.7.2-0.20190717214921-a17c1d78d5fb

(Though tthat particular sha1, a17c1..., doesn't apparently work anymore. I used this instead:

replace github.com/99designs/gqlgen => github.com/marwan-at-work/gqlgen v0.7.2-0.20190717214921-6209cacef23

I just added a replace in my go.mod file and ran the regular go run command to generate. Worked like a charm. 馃槉

Thank you everyone for trying out the wip branch.

Now that I have something that's close to being done for MVP, I am working off of https://github.com/marwan-at-work/gqlgen/commits/federation where I squashed all the wip commits (but didn't want to lose the original commits in the older branch)

Feel free to use a replace clause like mentioned above, and feedback is always welcome :+1:

Oh also, PR is opened above :)

It works great but it would be nice to be able to have the directives in the schema so it's valid. As it is now the generation complains that they cannot be redeclared.

@argoyle out of curiosity, why would you want to redeclare them in your own schema if gqlgen adds that declaration for you?

Mainly because my schema editor (in Goland/Intellij IDEA) complains that the schema is invalid and can't provide any kind of completion. 馃槃

@argoyle hmm, that certainly seems like a valid reason. Although I imagine if Apollo Federation becomes a standard, then Intellij will start considering those directives as built-ins and wouldn't complain.

I'd be happy to allow redeclaring federation-specific directives unless @vektah or someone with more knowledge has a different opinion :)

I can't seem to get the new code to run; I'm undoubtedly missing something obvious (I'm pretty new to go). I added this to the bottom of my go.mod:

replace github.com/99designs/gqlgen => github.com/marwan-at-work/gqlgen federation

and ran go run github.com/99designs/gqlgen. It downloaded the new module, it seems, and the marwan-at-work location is the only one listed in go.sum, seemingly pointing to the right commit:

github.com/marwan-at-work/gqlgen v0.7.2-0.20190830181151-63e6214f6aed h1:UEOE/lJ+igQti6dCiyGS6V+s0nCGPZ5UlwOxZjCI0A4=

But my generated.go file does not have resolve__service or resolve__entities or any other mention of federation.

I thought maybe the problem is I'm not using any federation-requiring keywords in my schema (yet), so I changed my schema to be like this:

type Query @extends {
  isOnZeroRatedNetwork: Boolean!
}

and then ran go run github.com/99designs/gqlgen, and it said:

schemaconfig: schema.graphql:11: Undefined directive extends.

So it seems like it's just not running the new code at all.

What am I doing wrong?

True that. And I'll survive copying them in just when editing the schema as well.

@csilvers Try adding federated: true to your gqlgen.yml (like here)

@BitPhinix thank you for the tip! I even looked at that file but totally missed the new keyword.

Now I am getting this error:

schemaconfig: entity.graphql:2: expected at least one definition, found }

As far as I can tell, entity.graphql is not mine; it's not clear it's a physical file at all. I'm guessing this error means my schema file is bad in some way?, but I don't have much clue as to what the problem might be.

@csilvers this error happens when you have no @key in your schema. Can you please double check that if you added @key to any of your types, that things do work?

So this is a good use case for maybe wanting to be a federated service, but not actually extend any types. I'll add a fix for it soon :)

That was indeed the problem! I added an (arbitrary) @key and now things compile.

Next issue: I see that a new file is auto-generated: service.go. Is there a gqlgen.yml config option to control its name and location? We have all our autogenerated files in a subdirectory, so for now I just manually move service.go there too after creating it. (It does seem to declare the right package, I'm not sure how that is happening actually.)

Once I manually move that to my subdir, and add

func (r *Resolver) Entity() generated.EntityResolver {
    return &entity{r}
}

to resolver.go (and make a few other resolver changes), everything works great!

@marwan-at-work It would also be nice to be able to specify the location of the service.go file in gqlgen.yml the same way as for the other files in case someone (nudge nudge) would like to have them somewhere else than the root of the project.

Edit: And just now I read @csilvers comment 馃槃

@marwan-at-work I played around a bit using your prototype and everything seems to work perfectly. The only thing that I noticed is that GQLGen generates invalid code now if you have no Mutations/Queries/Entities defined. Thanks a lot for your work!

I noticed another thing: using implements on an entity e.g.:

type Account implements Followable @key(fields: "id") {
  id: ID!
}

Seems to produce an invalid SDL by putting the key directive before the implements:

type Account @key(fields: "id") implements Followable

Edit:
I made a tiny pr to fix this: https://github.com/marwan-at-work/gqlparser/pull/1

I am a little interested into this topic 馃憖

I noticed a bug in @requires -- it doesn't work on the toplevel query. For example:

type Query @extends {
  requireeField: String @external
  requiringField: String @requires(fields: "requireeField")
}

The generated code requires you to implement a queryResolver.RequireeField method.

If I have time tomorrow, I'll take a stab at fixing this. ~I'm worried it's going to be a little awkward, because gqlgen doesn't really have a model for the root query like it does for other graphql types.~ (Edit: I think we may be able to just create one without too much trouble, although to avoid breaking compatibility things may have to be a little inconsistent for fields with @requires vs. fields without.)

Update to my previous comment: Apollo doesn't seem to support @requires on fields of Query at this time, so I'm going to follow up with them and then revisit.

@marwan-at-work I just changed my mind on the issue of being allowed to have the directives in the schema-file. I tried to upload the schemas to Apollo Engine and it complained about the directives being in there as well. Will bug the GraphQL IDEA plugin-author instead. 馃槅

What is the current state of this?

@nadilas the PR is pending another round of review from the maintainers. In the meantime, feel free to use the fork and try out federation with gqlgen and provide feedback if you have any :)

@marwan-at-work is there an idea of having the gateway generated in gqlgen as well? perhaps as a plugin?

@sdalezman, did you found a solution?

@marwan-at-work, is there also a desire in your thoughts to generate a gateway? Anything to replace this file: https://github.com/marwan-at-work/federation-demo/blob/master/gateway.js ?

@frederikhors what we ended up doing is taking a different approach than federation.

basically we realized that our services are pretty consistently structured. so we decided to do was use a go script to generate our schema by reading all the schema files from the sub-services and then write that to the updated schema.

we then have code that automatically proxies requests to those subservices successfully.

from a practical standpoint it's pretty close to the stitching setup, but doesn't use the federation itself.

the above setup also means that we can define data loaders at our central api layer and easily embed them in sub-service queries without much work.

the one problem is that at the moment, when a sub-service is updated it doesn't automatically update the central api. instead that kicks off an automated process to rewrite that schema and open a pr against the central api.

it basically has made it that apollo federation is a bit less interesting to us.

Currently, the only graphql federation gateway implementations I'm aware of in Go are:

Nautilus is based around the assumption that all your services are GraphQL Services. It uses the Node interface (Relay Gloabl Object Identification) to automatically federate between multiple services. This approach is quite similar to the approach Apollo Federation took. So all services have to comply to the Relay Global Object spec and you're ready to go. Nautilus gateway will analyze your services via introspection at startup time and generate the final gateway schema.

Why is this closed? Is it merged?

I was a Go developer but am doing Federation in Node. We have serious performance issue with Node because we have both CPU bound and IO intensive code. So I seriously want to implement new federated services in Go. I can still live with the Node Gateway.

851 has been merged, and there has been some follow-on work after that for further improvements. The current master supports building federation services in Go using the Apollo Gateway (in Node) such that we are using it in production at Khan Academy, and a few other places are as well. The next release will contain that support, and any additional polish that makes it in before then.

Good stuff! 馃殌 @vektah When can we expect the next release to be cut?

Sorry, this was closed because its landed on master. As @StevenACoffman
said we are just ironing out the last few bugs. There are some really basic docs at https://gqlgen.com/master/recipes/federation/

Next release is really soon, if you're using go modules you should probably be fine to use it now. There are migration docs here https://gqlgen.com/master/recipes/migration-0.11/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

msmedes picture msmedes  路  4Comments

cajax picture cajax  路  4Comments

theoks picture theoks  路  3Comments

andrewmunro picture andrewmunro  路  4Comments

sumanthakannantha picture sumanthakannantha  路  3Comments