Skip to content

Distributed GraphQL #291

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
Marfusios opened this issue Mar 7, 2017 · 8 comments
Closed

Distributed GraphQL #291

Marfusios opened this issue Mar 7, 2017 · 8 comments
Labels
question Developer asks to help him deal with some problem

Comments

@Marfusios
Copy link

Hello,

First of all, thanks for the library, it's a great piece of code.

I'm looking for an advice about making distributed GraphQL on top of this library.
I have a few microservices (A, B) and gateway. Web application sends requests only to the gateway (and doesn't know about other services).
I would like to make somehow schema partitioned between every microservice. So the gateway service won't define schema, just collects it from other services and provides to the client.

Visualized:

  1. Initial
Web app --- InstrospectionQuery ---> Gateway 
                                              --- InstrospectionQuery ---> service A
                                              --- InstrospectionQuery ---> service B
        <--- Merged schema result --- 
  1. Query
Web app --- Query ---> Gateway

B_Entity {
  BProp1,
  BProp2
}

Gateway --> Service B 
(and back to web app)

For now, ignore cross queries, like:

B_Entity {
  BProp1,
  BProp2,
  AEntity {
    AProp1,
    AProp2
  }
}

Where should I start? Implement custom IDocumentExecuter? Or is it better to integrate this library to every microservice and just resend request and merge responses?

@joemcbride
Copy link
Member

joemcbride commented Mar 7, 2017

I don't think there is a good answer to this one yet.

Some conversations from the JS community:
graphql/graphql-js#223
apollographql/apollo#39

GraphQL is pretty much designed around a single server architecture currently which makes this a bit harder. Here are a couple options I can think of:

  1. Only use GraphQL in the gateway

    • Other microservices are just typical rest+json endpoints
  2. Try a merged schema

    • We don't have a feature to create a schema from introspection currently, so you would be on your own
    • An alternate approach would be to use the "Schema Language" and map that to resolvers (kind of like graphql-tools) - also not a feature yet but one I'm pretty interested in (see Initial work for supporting a schema builder #362)
    • I don't think you need a custom IDocumentExecuter. You can add field resolvers that proxy to the targeted microservice. The harder part may be forwarding variables + arguments.
    • If you have types with the same name, you would have to provide some sort of namespacing, or just error.

@joemcbride joemcbride added the question Developer asks to help him deal with some problem label Mar 7, 2017
@OneCyrus
Copy link
Contributor

apollo is implementing it now

https://dev-blog.apollodata.com/graphql-schema-stitching-8af23354ac37
ardatan/graphql-tools#382

@OneCyrus
Copy link
Contributor

i'm exploring a bit on this topic. the schema builder in 2.0 is pretty cool for this. and it should be possible to implement the merging algorithm on top of this. the harder part is the type resolving. currently it looks like we need explicit types in the DI to be able to resolve additional types. There's no fallback to handle local unresolved types. Maybe we can introduce some kind of universal type which can route those unresolved types.

@joemcbride do you have an idea how you would implement the resolver logic?

@troydalldorf
Copy link

troydalldorf commented Nov 3, 2018

@OneCyrus @joemcbride Are there any updates on this topic? I have the same question as @OneCyrus for @joemcbride as to what the best strategy would be for implementing distributed queries (at a high level)?

@OneCyrus
Copy link
Contributor

OneCyrus commented Nov 3, 2018

@troydalldorf we started working on this in #592 though lately there's not much progress on our side. but this should change early next year as we want to push this forward.

@andrewtyped
Copy link
Contributor

We also have a microservice architecture in alpha which uses GraphQL to provide a gateway. Our approach is similar to GraphQL Hub's.

  • Each microservice implements its own GraphQL schema which is capable of independent operation. Resolvers in these schemas only access the public API surface of the microservice under test.
  • Each microservice's DI registrations for its GraphQL types are made publicly available.
  • A separate web service pulls in each schema and its DI registrations and merges them by inserting a ObjectGraphType with an empty resolver in each root object of the merged schema for each component schema.
  • The inserted ObjectGraphType contains all the fields of the component schema's root object.
  • Schema-level objects like directives are added from each component schema to the merged schema.

For example, suppose I have two schemas:

#Schema A
schema {
  query {
     name: "AQuery",
     AField1: Object,
     AField2: Object
  },
  mutation {
    name: "AMutation",
    AMutation1: Object, 
    AMutation2: Object
  }
}

#Schema B
schema {
  query {
     name: "BQuery",
     BField1: Object,
     BField2: Object
  },
  mutation {
    name: "BMutation",
    BMutation1: Object, 
    BMutation2: Object
  }
}

The merged schema would look like:

schema {
  query: {
    AQuery: {
      AField1: Object,
      AField2: Object
    }
    BQuery: { 
      BField1: Object,
      BField2: Object
    }
  }
  mutation: {
    AMutation: {
       AMutation1: Object, 
       AMutation2: Object
    }
    BMutation: {
       BMutation1: Object, 
       BMutation2: Object
    }
  }
}

Unfortunately I can't share the code which performs the merger because I don't own it. I can say it was not difficult to write.

We like this plan so far because the boundaries of each microservice are clearly marked by the top-level fields in each root object, and it's easy to test each component schema separately. The client, however, is slightly disadvantaged because they have an extra level of nesting to drill through before getting to their query results. We've accepted this trade-off.

If there are other disadvantages to this strategy we haven't advanced far enough to see them yet - both our microservices and their GraphQL schemas are simple, and their functions are distinct enough that we don't see value in trying to handcraft a schema that is aware of the overall system.

@sungam3r
Copy link
Member

Relates to #1233

@sungam3r
Copy link
Member

See #592 (comment)

I am going to close this issue due to lack of activity and the fact that it has been a long time since the original question. If the problem is still relevant, then it is worth creating a new issue and we will try to figure it out using modern approaches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Developer asks to help him deal with some problem
Projects
None yet
Development

No branches or pull requests

6 participants