apollographql / apollo-server

🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
https://www.apollographql.com/docs/apollo-server/
MIT License
13.81k stars 2.03k forks source link

Feature Request: graphql Server Chaining #4

Closed JProgrammer closed 8 years ago

JProgrammer commented 8 years ago

With the current focus on small independent microservices in the REST world it would be good to be able to chain multiple apollo servers together.

For instance you may have a single user repository in the company. A apollo server would expose a graphql endpoint to query and mutate these users.

An app server then needs to query this database for user name and address etc. the app server would expose via proxy a subset of queries from the user repository server with the schema being read from their.

The graphql proxy connector could then have extension points to transform the incoming/outcoming queries and results from the chained server.

helfer commented 8 years ago

@JProgrammer This is a pretty interesting idea, but I wonder whether it could actually be easier to just have the user schema in the app server (exposing only the parts you want) and making the query from there. A graphQL server is essentially a proxy, and I'm not sure yet whether it makes sense to chain them, or whether it's better to just push it all into the gateway (the app server).

Or maybe I misunderstood, and you're asking for a way to compose schemas rather than having one graphql server rely upon another for part of a query?

JProgrammer commented 8 years ago

@helfer The idea is that in the REST world you would have multiple small servers looking after small parts of the system, microservice, so that they can be independently upgraded, maintained, tested etc.

So if graphql/apollo is replacing the data stack of REST then I would like to be able to make small graphql servers to take responsibility of the service logic/database access then in an application or aggregate server that sits across these servers to serve the individual client queries.

stubailo commented 8 years ago

I'm curious what the benefit would be of having the microservices use GraphQL to communicate rather than REST. In my current mental model, the microservices still speak REST, and there is a single GraphQL server that composes all of the data. But perhaps there are significant benefits to using GraphQL everywhere!

JProgrammer commented 8 years ago

I guess with graphql-tools just being a express middleware there is not a large overhead for microservices to offer both REST and GraphQL.

With the end goal of apollo-server having meteor like reactivity having a server pass reactivity between servers will reduce load and distribute a single read/write operation across multiple clients and make a simple path for inter application communication.

A lot like how meteor server can connect to another meteor server over DDP rather than having to share state over REST.

helfer commented 8 years ago

Closing this, since it's almost three weeks old. Feel free to continue discussing it, and reopen if you have a specific use case that cannot currently be supported with the current implementation of apolloServer.

ejaxon commented 8 years ago

I am looking at a use case that may be well served by such a feature.

My interest is in open local government data (cities & counties) and, as an extension, in the ways that local government systems make data accessible internally as well. GraphQL strikes me as potentially a great way to provide such data both as a standard internally and via open data portals. Obviously the ability for clients to specify the shape of the data they want is important here (since the use cases that will employ the data aren't known in advance), but the validation and introspection capabilities of GraphQL are especially valuable.

One of the interesting aspects of open government data is that cross-organizational (e.g., different departments or agencies) and even cross-jurisdictional (e.g., the county in which a city is located) data queries are important. In many cases this will be a one-off task and can be left to the client, but I expect some queries to be common and important enough that organizations should provide an aggregated view. This might be done by a city, combining multiple department sources into a common portal or even pointing, say, to county, state or federal sources of related data. Or it might be done by a 3rd party, say an investigative journalism organization or an advocacy group.

It is certainly possible to create some kind of proxy server that could take care of this and perhaps that's the better way, but the fact that such a proxy would certainly need to be able to combine both GraphQL and REST endpoints makes me think that it would be better integrated directly into the GraphQL server. Also, optimizing such queries may be possible, but that again assumes built-in knowledge of the functioning of GraphQL, which resides best inside the same server.

@JProgrammer - perhaps it's worth re-opening this issue to discuss such a use case?

igrayson commented 8 years ago

I'm also looking at a problem I believe would be served by this capability.

@stubailo

But perhaps there are significant benefits to using GraphQL everywhere!

A large benefit I see is that I only need to express my schema once and in one format (gql), which is shared by my client, and the "end" servers that know how to service various sub-trees of the client's query. All my proxy server(s) should need to know is how to route subtrees of the query to org-specific services.

rogchap commented 7 years ago

@stubailo

But perhaps there are significant benefits to using GraphQL everywhere!

The same benefits you get from an API gateway using GraphQL is true for an internal microservice like query batching or caching for example. Why would you go back to REST, just because it's not externally facing?

AshleyAitken commented 7 years ago

I am interested in this as well. We have multiple subsystems each with a current REST Query API. Then there is a Gateway that has the public client REST Query API. The Gateway can do integration across the REST Query APIs.

I think it would be great if the Gateway could be a GraphQL server that aggregated the schemas from each subsystem GraphQL server. Clients using the Gateway GraphQL endpoint could then query across all the subsystems.

I guess what I am asking for is a datastore that can be another GraphQL server. I

jnak commented 7 years ago

Coursera mentioned a similar approach in their graphql talk. I think this is THE missing piece in a micro-service architecture:

If anyone is interested to work on it, please hit me up :)

ejaxon commented 7 years ago

This is something I might be interested in working on when we hit the need - at the moment we're building just the one API, but I expect we'll get there.

As a side note, we're building some data infrastructure where the base-level GraphQL API is actually automatically generated from metadata - curious if anyone else is doing anything like this. Just did an article on Medium about our approach.

helfer commented 7 years ago

I'm working on a small demo for this exact thing. I'll let you guys know if I have something to show.

rogchap commented 7 years ago

We have a micro-services architecture; we've built a graphQL endpoint for our apps to access (public) and then connect to a number of other services for varying things.

We needed to build a new internal (private) service; we built this as another graphQL endpoint and used apollo-client on the server.

This is working really well for us, I just love working with GraphQL over REST, and thanks to apollo-client there was no need to build a separate "client" application for a REST endpoint(s)

The only thing that I found I was repeating my schema definitions (and all the descriptions) in both systems. I also made my internal graphQL quite "flat" with everything on the RootQuery or RootMutation and only my public facing GraphQL more graph like.

AshleyAitken commented 7 years ago

The question for me is: Assuming we have a number of microservices with GraphQL APIs, how can we best implement a Gateway GraphQL API that offers queries across all the microservices?

It seems that automatically merging GraphQL schemas isn't too difficult (if that is what you wish to do and excepting namespace issues) https://github.com/graphql/graphql-js/issues/223 and we have a tool to help https://github.com/liamcurry/gql

The missing piece, in my opinion, is how to delegate queries for subgraphs of the gateway API to the microservice GraphQL APIs. Can the appropriate resolvers just pass on their subgraph queries? Do we need a client (or clients) on the gateway?

smolinari commented 7 years ago

I'm going out on a limb here, and continuing on Ashley's thinking, but there would seem to be a need here to basically prune (or copy) parts of the graph for each microservice, right? So, to define the microservice, we'd need

  1. An automation to prune/ copy the branches of the graph (probably more like a single branch) of the graph for each microservice.
  2. To change the resolver to hit the new microservice with a proper GQL query, instead of it resolving to grabbing the data or service itself in some other format.

I've also been contemplating a microservices architecture, not using GQL, but rather using gRPC (and automating this too), because gRPC has somewhat better (more official/ under one roof) support for different languages than GQL does and all the benefits GQL offers (but specifically for microservices). Plus, gRPC has type definitions which are language agnostic through Proto3. Well, it seems it does. 😄 I'm learning. This is all blue sky thinking on my part, but it shouldn't be too hard to build a parser, which translates GQL to proto3 (or the other way around!!!) and away we go!

Scott

rkstar commented 7 years ago

@rogchap how did you implement apollo-client on the server? i'm interested in this too! i have a web server that i need to get connected to my data api via graphql instead of having to set up rest endpoints for server->server data calls.

my current option is to hit the db directly from my web server to do some things and let the client hit the graphql server for everything else. it seems kind of silly to be hitting the db from 2 different places.

rogchap commented 7 years ago

It's very simple, we use graphql on an internal server and use apollo client on the other server. Although this does work, I'd recommend gRPC too. We're planning on refactoring to use gRPC for server-to-server and graphQL only as the public facing API

espoal commented 7 years ago

One use case I thought about is to have one GQL server to handle auth & permission logic, chained with one handling the real data.

So you authenticate with the public facing server, so that you can pass queries to private servers.

I frown upon using gRPC, thus adding another library in my codebase. Using GQL only would be a benefit.

Why can't GQL serve all our needs?

smolinari commented 7 years ago

Why can't GQL serve all our needs?

It can, once all the necessary tooling is made available. :smile:

The only question is, when will it come? Currently GraphQL doesn't support what gRPC does. When it does, then sure. It can cover all the API bases.

Scott

jnak commented 7 years ago

Why can't GQL serve all our needs?

@servermeta While that was not one of the design goals of graqhql, I think there is not fundamental reasons it could not be a graph enabled rpc layer.

The only question is, when will it come? Currently GraphQL doesn't support what gRPC does. When it does, then sure. It can cover all the API bases. In my opinion the main thing missing is more robust error / exception handling. At the moment errors are mostly useful for debugging purposes and not useful for rpcs. You could achieve this in ad-hoc manner (see https://medium.com/@tarkus/validation-and-user-errors-in-graphql-mutations-39ca79cd00bf) but I'd rather have the graphql spec defined this so clients and servers are all on the same page.

@smolinari What do you think is missing in Graphql compared tp gRPC?

J

smolinari commented 7 years ago

@jnak - These points are off the top of my head and from my limited knowledge.

  1. gRPC supports a number of languages out of the box.
  2. The client code can be automatically generated in any of the supported languages.
  3. gRPC supports full duplex streaming.

Scott

jnak commented 7 years ago

@smolinari Interesting. With regard to 1. and 2., I think graphql took the route of building very idiomatic client and servers in each language by building a spec. While it is harder to bootstrap as an ecosystem, I think medium term it was right choice. When I look at https://github.com/chentsulin/awesome-graphql, I feel we are almost there. Regarding 3., I'm hopeful that graphql subscriptions (http://graphql.org/blog/subscriptions-in-graphql-and-relay/) can evolve into a solid bi-directional layer. Future looks bright :)

smolinari commented 7 years ago

@jnak - That's why I said "It can, once all the necessary tooling is made available." 😄

I love GraphQL's future too. Because, I believe it is built much more to be a client based API (if you can call it that). By that I mean, the client has much more flexibility in getting only the data it needs and defining the calls on its own. GraphQL is a great end-user(GUI client)/ server API system. This kind of API system isn't possible with gRPC or rather, gRPC is what I consider more server or service based and works better in a microservices environment. They say you can use gRPC for mobile clients, but I still think GraphQL beats it out in this area of API needs.

Scott

gilbert commented 7 years ago

Here's a use case I think solving this issue would fulfill. I have a central graphql server that my client interacts with. Behind it are several legacy REST services. So far, so good.

Next, we want to expose our legacy postgres database to our central server using something like postgraphql or join-monster. This is good because it can give a client access to arbitrary but safe queries. But here's the problem: we want to have our central server handle auth., and then pass the relevant graphql query along to the db afterwards.

It would be nice if there were a way to grab that db subquery, I think.

stubailo commented 7 years ago

BTW we're calling this "Schema Stitching" and here's the implementation! https://github.com/apollographql/graphql-tools/pull/382

hooray!

please chime in there.

jnak commented 7 years ago

@stubailo That's awesome!! Can't wait to see what people do with this!

loganpowell commented 6 years ago

... and history is made