Generate schema on each request

387 views
Skip to first unread message

Søren Bramer Schmidt

unread,
May 27, 2016, 8:52:11 AM5/27/16
to sangria-graphql
Hi Oleg - It's been good to meet you in Berlin :-)

We are about to investigate if Sangria would work well for us in the backend for graph.cool. 

A special requirement for us is that we need to be able to change the schema for a project at runtime. In practice this means that we keep an internal representation of the schema in a data store and build up the Sangria representation of the query on each request.

I would really appreciate your thoughts on this approach as well as any issues you could think of that might show up when using Sangria in this way.


Thanks!

Oleg Ilyenko

unread,
May 27, 2016, 3:37:19 PM5/27/16
to sangria-graphql
Hi Søren,

Indeed, it was great to meet you a talk about all things GraphQL! :)

There is nothing in sangria that will prevent you from doing this. In fact it is very easy to do. Sangria itself does it a lot as well. The project now contains about 900 tests and most of them are creating schema on the fly for every individual test case. I recently started work on CATs support which takes it to the next level: the executable schema is created dynamically based on the IDL definitions. You can find the code in a separate branch: https://github.com/sangria-graphql/sangria/compare/cats

In our company we use GraphQL/sangria as well and we already thought on implementing very similar functionality. At the moment the schema is pretty static, but we have user-defined data structures in form of custom product attributes. In order to provide nice GraphQL API for these, we would like to generate parts of the GraphQL schema based in the definitions that come from a database. The only thing that prevented us from doing it so far is the fact that it simply too expensive to load all these custom data types from the database on every request, or at least we would like to avoid if possible. I don't think that building an in-memory representation of GraphQL schema would be an issue in this case. Creating additional objects for it has it's costs in terms of garbage collection, but I doubt that it will have big impact, especially in comparison to amount of data that we need to load from the database and time it takes to load load this data. 

At the moment it's just an assumption, which we need verify first. But if, indeed, it takes too much time to load this data, then there are number of ways how this can be optimized. One possible solution is to use something like in-memory LRU cache which will build in-memory schema on demand and evict it if it is unused for some time and cache size has grown too big or there are new changes in the generated parts of the schema. 

Another possible solution is to use the fact that it's scala which has pretty rich ecosystem nice mature libraries. For example one can use an akka cluster and dedicate a cluster singleton actor for every tenant of the system. These actors (or set of actors) will encapsulate all of the interactions with the schema of particular tenant. I think this kind of approach will require a bit of investment in infrastructure code, but in a long term may provide a very scalable and flexible solution.

tl;dr it is possible and very easy to do, but you need to measure the impact on performance (CPU utilization, garbage collection, etc.) and optimize it if you see that it is necessary. But I guess it's not specific to sangria or scala. I would also take very similar approach if I would implement this kind solution with the GraphQL reference implementation and nodejs.

Cheers,
Oleg

Søren Bramer Schmidt

unread,
Jun 6, 2016, 10:31:46 AM6/6/16
to sangria-graphql
Thank you for the detailed Response Oleg!

Your suggestion to use Akka is particularly interesting. Akka is what got me into scala 5 years ago so that is certainly something we will consider. Our plan is to do a full implementation without Akka and measure the throughput we can get with the simple setup before we start getting fancy.

Expect lots of questions from us over the next few weeks :-)


I hope you had a good time at React Europe!

Peter Hunsberger

unread,
Jan 23, 2017, 10:40:20 AM1/23/17
to sangria-graphql
Excuse me for jumping in to this thread but this is exactly what I need to do.  Can you point me at an example in GitHub where a dynamic schema (of some complexity) is constructed?  The only things I'm spotting so far look rather trivial and aren't giving me much of an idea as to what is needed.

Søren Bramer Schmidt

unread,
Jan 23, 2017, 10:51:37 AM1/23/17
to sangria-graphql
Hi Peter :-)

We are using this approach in production at Graph.cool with great success. At a high level, this is what we are doing:

Whenever the schema representation changes, we pregenerate a hierarchy of case classes to describe the schema and serialize this to redis.
At each request to the api we load this serialization from redis, generate a Sangria schema and call Executor.execute.
The overhead is low enough that we have not yet investigated keeping the schema in memory using either a lru cache or actors.

Anything in the overall architecture you would like me to expand on?

Peter Hunsberger

unread,
Jan 23, 2017, 11:04:49 AM1/23/17
to sangria-graphql
I'm somewhat new to Scala so I might be missing something but it isn't readily apparent how to dynamically generate a hierarchy of case classes though I've somewhat rigged up a bit of that.  What's really escaping me at the moment is how to actually generate the Sangria Schema once you have those?

Peter Hunsberger

unread,
Jan 23, 2017, 12:21:29 PM1/23/17
to sangria-graphql
Guess I should add that my approach so far has been based on extending DefaultIntrospectionSchemaBuilder and one part I'm getting hung up on is creating the field resolution logic on the fly

Oleg Ilyenko

unread,
Jan 23, 2017, 12:27:45 PM1/23/17
to sangria-graphql
Maybe this example will hep in your case:


It's the code behind graphql-toolbox proxy:


The example uses `DefaultAstSchemaBuilder` to define resolve functions based on the directives. It should be very similar with `DefaultIntrospectionSchemaBuilder`.

Cheers,
Oleg

Peter Hunsberger

unread,
Jan 24, 2017, 4:44:26 PM1/24/17
to sangria-graphql
This has gotten me pretty far but I'm now starting on mapping the Schema instance to the concrete data instances and for the life of me I can not find where the "Ctx" type definition that is used all over the place is defined.  In particular, I'm needing to define the resolve function for the schema.
Reply all
Reply to author
Forward
0 new messages