Open robotex82 opened 4 years ago
Using the Rails.application.routes will not perform as well as using Agoo routes. Using Agoo for routing allows static assets to be loaded directly. It also means the GraphQL endpoint is accessed directly instead of going through rails. Have you considered this? If so, is there a reason you decided against that approach?
Thank you for your advice! This is a thing that has to be taken into consideration when it comes to performance.
I'd like to stay in the bounds of what i feel is "the rails way" to be able to have a drop in graphql api that just works as any other rails engine. If performance becomes an issue one could provide an optimization guide where the app is mounted i.e. via the config.ru file of the rails application. But for the simplicity of usage (coming from a rails perspective) this should be optional.
I hope i was able to clarify the situation.
I understand. I'll have to do some research on how the Rails routes work. If you have a good understanding of what is needed that would help. Do you know methods the mount must respond to?
Rails can mount vanilla rack apps via routes:
Rails.application.routes.draw do
mount SomeRackApp, at: '/foo'
end
https://guides.rubyonrails.org/routing.html#routing-to-rack-applications
Great, thanks. That should be possible. A bit of overhead going back and forth with strings but if performance isn't a concern it should be possible. Being a performance geek it does make me cringe though. 😄
I feel you concerning the performance. Nowadays people tend to prefer to pay a bit more for servers than to pay developers for optimizations...
I started working on this today. The approach basically take the request and reforms that request and make another http request. I was wondering if Rails supported a redirect. If so then instead of a mount it would just redirect the request to /graphql
. Is that possible?
I'm not sure if I understand. I'll make a small example app where we can expore ideas.
I created a test app: https://github.com/robotex82/rails-agoo-graphql-test
The app is available here: http://rails-agoo-graphql-test.herokuapp.com/
I added two rails engines (i called them frontend and backend) with separate graphql endpoints. Both have graphiql UIs to fiddle with them.
The frontend graphql endpoint is at /graphql. The corresponding graphiql interface is at /graphiql.
The backend graphql endpoint is at /backend/graphql. The corresponding graphiql interface is at /backend/graphiql.
At the moment graphql is implemented as dummy rack apps:
The use case would be to replace those dummy apps by some piece of agoo rack app where the schema can be built on to of it.
If this is made with a redirect, where would it redirect to?
Let me try to explain a bit better than I did the first time.
So any web server will accept requests and then form responses based on the URL path. Something like this:
/-asset/logo.jpg-->
request --> server ---graphql-->
\-user/123-->
With Agoo doing the routing and using Rails the diagram becomes:
/-asset/logo.jpg-->
request --> agoo ---graphql-->
\-*-->rails-->user/123-->
This is the most direct and gives the best performance. If Rails is to do the routing then this is the diagram:
/-asset/logo.jpg-->
request --> agoo -*-->rails---graphql-->???
\-user/123-->
So what I think you want is to have the ???
be the Agoo GraphQL handler. Conceptually this is what it would look like:
/-private/graphql-->
/ /-asset/logo.jpg-->
request --> agoo -*-->rails---graphql-->{http://localhost/private/graphql}
\-user/123-->
The question is how to implement the part in {}
. One approach is to make a Agoo::GraphQL implement the #call()
method. This ends up being pretty convoluted. The second approach I was asking you about would be for the path in {}
to be an HTTP redirect that would call out over HTTP to get the response.
You also suggested something else with your mention of two servers. The redirect could go to a different server entirely.
Decoupling the graphql part of agoo from the usage of agoo as server opens up the implementation to many more use cases (like the simple usage in rails or any other rack compilant application).
So to keep it in the bounds of the rails application as you have pointed out the correct solution is to implement the "???" part in your diagram. This would be a rack app that you can feed a GraphQL schema. This could be either by inheritance or when calling it:
I.e.:
# app/graphql/my_graphql.rb
class MyGraphql < Agoo::Graphql::RackApp
class Schema
end
def schema
Schema.new
end
def sdl
"type Query { hello: String }"
end
end
# config/routes.rb
mount MyGraphql, at: '/graphql'
With such a construct one could for example implement a code first sdl generator and many other things.
"Correct" is probably a matter of priorities but I can see your desire. That approach will take a fair amount of reworking of the Agoo code base so it's not going to happen right away. Lets keep this as an open issue though and at some point I'll separate the graphQL component from the server.
Sorry, "correct" was meant from the rails perspective. I apologize for this clumsy choice of words.
I've seen in this file https://github.com/ohler55/agoo/blob/develop/example/graphql/song.rb that graphql seems to be enabled by this line:
Agoo::GraphQL.schema($schema) {Agoo::GraphQL.load_file('song.graphql')}
I assume that there would be the need to some kind of interface to separate the GraphQL stuff from the server. As agoo is already a rack server, could something like this be desirable?
Actual + With Rack Interface
|
+-------------------+ | +-------------------+
| | | | |
| | | | |
| Agoo Server | | | Agoo Server |
| | | | |
| | | | |
+-------------------+ | +-------------------+
^ | ^
| ? | | Rack-Compatible Interface
| | |
+-------------------+ | +-------------------+
| | | | |
| | | | |
| Agoo GraphQL | | | Agoo GraphQL |
| | | | |
| | | | |
+-------------------+ | +-------------------+
|
|
+
If this i a viable possibility can you point me in a direction to what needs to be done? Where is the interface between the http server and the graphql in the actual implementation (the question mark in the ascii picture).
The diagram isn't quite right. Requests hit the server first. Next the server looks at the URL path and picks a handler. The GraphQL component is one of those handlers. Handlers are chosen before converting a request to Ruby. Thats on of the things that makes Agoo fast. Routing is all done in C. If the URL path is for a Rack handler then a Ruby request object is created and processed.
With that in mind the Rack call would then have to invoke the GraphQL handler but that expects lower level data such as a string to parse or a URL path to pull apart. The effort to separate splitting the code to allow entry from a different point. That is compounded by the API being multi-threaded. So, yes, it is possible but will take some time.
I see, so it's more like that:
1.) Agoo as Server with builtin GraphQl and Rails as rack app (This is already possible)
+---------------+ +---------------+
| | Rack Interface | |
| Agoo Server | (config.ru) | |
| +----------------->+ Rails |
| Agoo GraphQL | | |
| | | |
+---------------+ +---------------+
+----------------------------------------------------------------------------------------------+
2.) Rails with agoo GraphQL mounted as RackApp in Rails routes (This would be possible)
+---------------+ +---------------+ +---------------+
| | Rack Interface | | Rack Interface | |
| Agoo Server | (config.ru) | | (rails routes) | |
| +----------------->+ Rails +------------------->+ Agoo GraphQL |
| Agoo GraphQL | | | | |
| | | | | |
+---------------+ +---------------+ +---------------+
+---------------------------------------------------------------------------------------------+
3.) Rails and Agoo GraphQL side by side as rack apps configured in config.ru (This would be
possible, but I don't see many use cases)
+---------------+ Rack Interface +---------------+
| | (config.ru) | |
| +------------------------------>+ |
| Puma | | Rails |
| +-----------+ | |
| | | | |
+---------------+ | +---------------+
|
|
|
| +---------------+
| | |
| | |
+------------------>+ Agoo GraphQL |
| |
| |
+---------------+
+----------------------------------------------------------------------------------------------+
Yes, more like 1 although maybe this is more accurate since Agoo GraphQL is a separate handler in the code.
+--------------+ +--------------+
| | | |
| +--------------->+ Rails. |
| Agoo Server | | |
| +----+ +--------------+
| | |
+--------------+ | +--------------+
| | |
+---------->+ Agoo GraphQL |
| |
+--------------+
I agree that 2 and 3 would be possible if Agoo GraphQL supported the #call()
method. 3 might be a littler trickier though.
Cases two and three should both work with the same interface. Because its all rack.
Is there anythink in ruby that can be done or is it all C? I can assist with the ruby stuff, but my C knowlege is, lets say, rudimentary at best.
It's really all C.
As for case 3, the issue that may come into play is the package initialization that right now includes the server so to handle case 3 all GraphQL code would have to be completely separate with no dependencies on the server. Since the GraphQL part is multithreaded it might mean that both a single threaded API as well as the multi-threaded API might have to be supported. Once for performance and one for Rack compatibility.
Its sad that my C skills are virtually non-existent.
I totally forgot the initial use case i tried to explain here at first. Coming from rails this would be the "default stack" integration. This would be the most important from my very rails centric perspective:
4.) Rails and Agoo GraphQL side by side as rack apps configured in config.ru (This would be
possible, but I don't see many use cases)
+---------------+ +---------------+ +---------------+
| | Rack Interface | | Rack Interface | |
| | (config.ru) | | (Rails routes) | |
| Puma +--------------------->+ Rails +----------------->+ Agoo GraphQL |
| | | | | |
| | | | | |
+---------------+ +---------------+ +---------------+
Since the API is #call()
in all cases other than the Current one it would in theory work. Like I said though. It is a lot of work and not going to happen over night.
Ok, thank you for looking into this! I'm very much looking forward into using the agoo graphQL in Rails!
It can already be uses with Rails just not using the Rails router. The request is on the list though.
I have been thinking about using the graphQL implementation in a Rails app. To do this I'll have to mount a graphQL schema inside the rails routes as a rack app:
Could this be possible?
My goal would be to write an extensible schema for an existing ruby on rails cms.