-
Notifications
You must be signed in to change notification settings - Fork 51
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
Feature Request: GraphQL Subscriptions Implementation #66
Comments
Hi @ianks , Thank you for bringing this up. @ohler55 already started working on GraphQL for the Agoo server and synchronizing the API and approach was previously discussed. Personally, I'm all for it, I just didn't have the time to dig in to GraphQL and I wanted to learn more before I could work out (or contribute to) a sustainable design that will be both performant and liberating. I also can't help but wonder: is it impossible to implement GraphQL subscriptions and queries either as Middleware or an App using the the iodine server? If possible, would it better to place GraphQL support into a separate gem? Anyway, I'm hoping a discussion could provide a better understanding of this requested feature, making the GraphQL support and API as easy to use and as effective as possible. Kindly, |
I've got it working for Agoo. I need to update Agoo-C so you have an example. Maybe we can meet up and figure out how to us it in April when I am in Boston for the marathon.
…On March 10, 2019 9:32:06 AM EDT, Bo ***@***.***> wrote:
Hi @ianks ,
Thank you for bringing this up.
@ohler55 already started working on GraphQL for the Agoo server and
synchronizing the API and approach was previously discussed.
Personally, I'm all for it, I just didn't have the time to dig in to
GraphQL and I wanted to learn more before I could work out (or
contribute to) a sustainable design that will be both performant and
liberating.
I also can't help but wonder: is it impossible to implement GraphQL
subscriptions and queries either as Middleware or an App using the the
iodine server? If possible, would it better to place GraphQL support
into a separate gem?
Anyway, I'm hoping a discussion could provide a better understanding of
this requested feature, making the GraphQL support and API as easy to
use and as effective as possible.
Kindly,
Bo.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#66 (comment)
|
@ohler55 - I'm traveling in the UK and the EU until mid May or June, so I think the discussion would remain "virtual" for now 😔 I'm happy you've got it working 🎉 B. |
The main issues we would have with Agoo's imementation are:
It is totally possible to build it with Iodine server, but building it right one time would benefit a lot of people IMO. Hope that helps, please feel free to ask me any questions. We have a fairly advanced setup and would love to be the an rats for this experiment 😀 |
Let me jump in and see if I can get some clarification.
I would be very happy to have someone help get the GraphQL functionality more friendly. What is it about the graphql gem that you like over standard GraphQL defined with SDL? |
|
Also, I'm interested in the relationship of Agoo <-> Iodine. Do they work together in certain ways? |
It sounds like supporting the adapter API might be the quick win and then leave the other when performance is needed. Bo and I collaborated on a Rack spec proposal to add support for websockets. We are both interested in providing high performance web servers first and less concerned with who's server is better. So competitive but in a friendly, cooperative way. Did I get that about right, Bo? |
I think I missed a step - which adaptor API? This one? ...doesn't look friendly... but maybe I need to better understand your needs.
I think @ohler55 put it nicely: "We are both interested in providing high performance web servers first and less concerned with who's server is better". Neither of us seems concerned about competition. Personally, I just want to make iodine (and the facil.io framework) the best it could be. Although, I have to admit, that I often feel that we're both offloading different framework features onto the servers to make things work faster. This makes the difference in approaches more pronounced. For example, Agoo supports a request router (which I want to design differently) and iodine offers a Mustache template engine and Redis connectivity (they come with the facil.io framework). |
so that adapter interface is the low-level interface which Iodine would implement, the actual user-facing portion is documented here: https://graphql-ruby.org/guides#subscriptions-guides |
I looked at the APIs a bit. Am I correct in understanding that the graphql gem uses ActionCable for subscriptions? If that is the case then both Iodine and Agoo might already be compatible as both support the Rack hijack option. Am I missing something? With the quick look I wasn't able to figure out how the gem actually gets called by the server. Does it expect to be the server itself? Would you mind giving use cases for connections, lookahead selection, and JSON schema output? It seemed like the first two are necessary only due to the nature of the gem's API but, again, I don't have any experience using the gem so may be missing the point. |
ActionCable is one possible adapter, if you use Rails. Not everyone uses Rails (we don’t 😀). Also, wouldn’t the performance of the Action able adapter be worse than using the supported Iodine / Agoo / Rack-Proposal websocket interfaces? The other supported adapter is for For lookahead, we use it to determine whether or not we need to perform potentially expensive joins on a DB table. Say you had a {
posts {
id
title
// would want to join if we had selected comments
}
} For connections, it offers a conventional mechanism for dealing with pagination (https://graphql.org/learn/pagination/). It handles the implementation details of dealing with paginating relations in a uniform way. JSON schema output is crucial for integrating with Apollo, which reflects on the metadata to handle caching/code generation for typescript, etc. |
Yes, ActionCable is much slower. When subscriptions are supported I expect to use the Iodine/Agoo web socket approach. look-ahead: I understand the concept of look ahead. What I didn't get was why it was needed if the Ruby code can see the query. Wouldn't it have all the information it needed to optimize the database queries? connections: So connections are just the graphql gem's approach to pagination. Can I assume any pagination approach would work for you as long as the API was reasonable? JSON Schema: Generating JSON schema should be an easy addition but I'm not sure what the schema would be for. Do you provide a graphql query and then ask what the JSON schema would look like? |
WRT to connections, not just any API, the GraphQL community has pretty much rallied around the Connection interface and there is a lot of tooling and code written for it. So not using Connections would cause incompatibilities. Take a look at some of public GraphQL APIs such as Github, they almost all specifically use the Connection interface. Yes but that would require diving into the AST which is not the most maintainable approach Sorry for being unclear about the JSON schema, it's mainly used for developer tools such as apollo-codegen. |
connection: got it, thanks. I'll do some digging. JSON schema: The schema is for the JSON response to some query, right? Or is it something else? I'm just looking at how I could add that so knowing what the schema is for would help. look ahead: I'm still not 100% on this so I'll have to do some more research. Thanks for your patience. |
I might be quiet, but it's because I'm listening and learning. Let me see if I understood correctly:
Yes, it probably would be, both in terms of memory consumption and in terms of speed... however, where speed is concerned, much of the performance hit is related to the ActiveCable pub/sub design rather then the extra IO reactor (which consumes more memory but should have a smaller performance penalty).
Is this something that the server should handle? I was under the impression that the GraphQL could be an almost "pass-through" to the database, except for some filtering and/or validations performed by the application. |
Let me answer to start with and then @ianks can correct me where I missed the mark. • GraphQL queries and mutation are generally received over HTTP or HTTPS. The GraphQL spec in regard to subscriptions is more open so WebSockets, SSE, or just an open connection would in theory be fine. I think for Iodine and Agoo WebSockets and SSE are a natural fit. • GraphQL is used to define an API. In order to bypass Ruby and go directly to the database would require either a database that has a GraphQL endpoint (I've got one :-) ) or a web server that does the conversion. The thing is GraphQL provides a lot of help building responses but it provides no structure for queries other than names and args. There is no SQL like component to identify data. That has to be implemented by the application. • Going by the GraphQL specs the endpoint can be anything although • The short answer is yes. Each client could subscribe to the same field and expect back different structures in the response. My plans for Agoo are to support server handling of the subscriptions based on the field/method but also allow the Ruby side to initiate the publish. Both would be configurable to both could be used or one or the other. I've kind of got the details worked out except for how to unsubscribe. The GraphQL spec is vague on how to do that from an API perspective. I have to do a little more searching to see what is common. At the very least the application (Ruby) would be able to cancel the subscription but in most cases I'd expect the client to initiate the unsubscribe.
It is a common misconception to think of GraphQL as a database front end. It is a way of describing an application API. If the application chooses to map the graph nodes or objects to a database that is the choice of the application. I suspect @ianks can describe more how heavy or light that layer is between the server and the database. I still haven't figured out what it is the server needs to provide for look-ahead. Probably because I don't know the internals of how the graphql gem interacts with the rest of the Ruby application. |
Most graphql calls will be over HTTP. Only subscriptions would use websocket/SSE.
That's one way to do it, but doing so removes many of the benefits of using GraphQL. GraphQL can be used to aggregate all types of data, some could be queries from the DB, others could be calls to an API, etc. Coupling directly to the DB takes away that ability.
Yes there definitely should. We do this. Say for example you are building your application "monolith-first", meaning you deploy one server which has multiple logical "apps". In our example, we have one endpoint for each app which corresponds to:
You can use one endpoint and implement authorization, etc. But it gets messy quick.
Can you post an example of what you mean?
No, application logic can handle this as long as there is a decent API for this. graphql-ruby handles this already. |
@ianks I'm putting together a list of features to add to the GraphQL feature. I have some holes in my understanding of what you are looking for though. So far the list is:
Interested in helping move Iodine and Agoo forward with your expertise? |
@ianks , Again, thank you very much for taking the time to describe your present (and possibly future) requirements. I'm sorry for my long inquiries and messages, I'm just trying to understand better. Form what I understand so far:
I think I summed up the discussion so far, right...? |
@ohler55 and @ianks , from what I can tell, there are three possible solutions (please correct me if I'm wrong about this):
@ianks - I believe that in your case, considering all the hours already spent on developing using @ohler55 - However, for future greenfield projects, it's possible that integrating the lessons learned here into a common GraphQL API for iodine and Agoo (the third approach) might be interesting and helpful. |
@boazsegev I think option 1 does not preclude option 3 which is good. |
👋 Just thought I'd link https://github.com/Envek/graphql-anycable which might provide some reference for how GraphQL subscriptions can be delivered on another transport (I admit, I haven't looked into it a ton!). |
@rmosolgo thank you! https://github.com/Envek/graphql-anycable/blob/master/lib/graphql/subscriptions/anycable_subscriptions.rb demonstrates the interface I was proposing to use perfectly 😀 |
Hey everyone Robert already mentioned graphql-anycable gem (which could be adopted to support Iodine as well, I think). Also, take a look at this comment: anycable/anycable#160 It sheds the light on how subscriptions are implemented in Action Cable. |
Hi @palkan , Welcome to the discussion and thank you for the link and your input. It's a slow discussion on my part, as I don't use GraphQL in any of my projects, so I don't have enough of an understanding to implement iodine support for it just yet. As far as the comment goes, I don't think I understand how a On the other hand, iodine supports server-side subscriptions ( |
GraphQL has become a staple in the Ruby community for building APIs. GraphQL subscriptions work on top of GraphQL to add real time data streaming, and has powerful client side implementations such as Apollo.
Currently, the only FOSS implementation for graphql subscriptions in ruby is the ActionCable implementation. Obviously, there is a lot to be desired performance wise from this implementation.
I think Iodine could attract a lot of users who currently have to use the AC version. What are your thoughts on including something like this in Iodine?
The text was updated successfully, but these errors were encountered: