GraphQL Query Rewriter
github.com
github.com
Instead of that, i'd personally recommend either sticking with your old schema if the change is as superfluous as the one mentioned on the project's README (changing the type of the `userById(id)` field parameter from `String!` to `ID!`), or shamelessly embracing versioning your fields. In the case example case mentioned on the README, that could mean adding a @deprecated directive on the `userById(id: String!)` field, and then adding a new `userByIdV2(id: ID!)`. Users of the new field can alias it on to a friendlier versionless name, like:
query {
user: userByIdV2(id: 123) {
...
}
}
This way, the changes on the schema are much more explicit: users can still use tools like GraphiQL or schema-aware text editor plugins to write their queries, while receiving feedback about their use of deprecated fields, and what they can do about them :)[1] Like Intellij IDEA's graphql plugin https://plugins.jetbrains.com/plugin/8097-js-graphql [2] https://github.com/graphql/graphiql
I guess the difference then boils down to whether you're OK with having a bunch of deprecates stuff in your schema (you can also remove those fields once they are not used anymore) and some "V2", "V3", etc in your field names, or your prefer having a more pristine schema but paying some price of discoverability and tooling support for those deprecated features.
Stringly type is too hard to be manipulated.
query { user { id name } }
why not
query: { user: { id: true, name: true, } }
Insofar as JSON is a type system, it's a weaker one than GraphQL, and would be a lot more verbose. Consider the query
query(id: Int, hasUser: Boolean) {
@include(if: $hasUser)
user(id: $id) {
name
}
}
It would be possible to represent this in JSON, but it would be a lot less elegant. {
"query": {
"args": {"id": "int", "hasUser": "boolean"},
"fields": {
"user": {
"args": {"id": "$id"},
"fields": {"name": true},
"includeIf": "$hasUser"
}
}
}
}
The JSON still depends on stringly-typed values like "$hasUser", but it's much harder to read and has many more unnecessary characters.EDIT: if you want to manipulate GraphQL queries, you need to parse them[1] and then look at the AST. This is not very well documented, so the best way of doing it is by experimenting with the values you've got, and then verifying your approach against graphql-js.
With param and fragments, the json would be too verbose, so you'd end up by always building your queries programmatically, so sharing queries between GraphQL implementations and/or runtimes/languages would be harder.
GraphQL language for queries and schema adds a layer that describe what your runtime and/or compile time has to conform with, which is incredibly helpful for stacks with heterogeneous environment.
In the end, you can always parse and generate those full text documents and manipulate them programmatically, as much as you want (just be cautious with perfs). So the apparent fragility has many ways to be addressed, with a huge advantage of having common ground on all stacks.
With dynamically generation of query, JSON parsing is easier than stringly type. You don't need a library like graphql-tag to do that.
Instead of posting a string body request, you post a JSON request, which is the standard way for long time.
In general, stringly type graphql query is not a fine choice to me.
GraphQL is a well-defined syntax that can be validated by both client and server. An invalid query can be rejected with a syntax error.
Yes, it is harder to dynamically construct a GraphQL query on the client, but you shouldn't do that anyway. The language has directives and variables that can introduce dynamic elements.
Graphql query also has specification, and you can encode it with JSON format, too.
WHy not ?
serialize(array('1' => 'elem 1', '2'=> 'elem 2', '3'=> 'elem 3'));
// a:3:{i:1;s:6:"elem 1";i:2;s:6:"elem 2";i:3;s:6:"elem 3";}
There are a lot of advantages to creating a custom syntax. In your example what does `query: { user: { id: 1, name: "true", } }` yield? How do you represent fragments? How do you represent variables and directives?You could implement conventions like `$ref`s in JSON schema, but then you've ended up creating another custom syntax... just this time it's piggy backing on JSON instead of plain text.
to me one of the important points of graphql is that it isn't json.
If you end up using query rewriting to upgrade client queries, you'll end up very quickly with divergent SQL-schemas spread across many clients with little proper way to identify (client A module B was written targeting DB v0.1, but module C was looking at DB v0.2, and client B was only written when v1.0 released; A was upgraded by query rewriting from v0.1/0.2 to v0.5 and then v1.0, so the codebase still features ancient references, and applies two rounds of rewrites to find the final query output)
[1]https://en.wikipedia.org/wiki/Confluence_(abstract_rewriting...
Though I don't know how much effort I would spend on trying to make this work.
With query rewriting, its a continual patch, which applies both against the old queries.., and when the old queries are modified; that is, two divergent codebases now exist, referring to different schemas, but unknowingly one codebase gets warped into a different universe where its query somehow works.
Both codebases continue to exist, and continue to be worked on. Divergent, yet somehow converging. Every client hit by query rewriting is another divergence.
The issue is that the codebase’s query in fact needs to be rewritten.. once, and finally! If you only modify it in-stream... then the rewrite rule must exist until the end of time, or the codebase is updated manually.
So really you want a way to patch codebases you probably don’t control.. but I think if you can solve that, you’ve solved APIs everywhere
You want to rewrite at compile-time, rewriting the codebase itself, and save the changes to version control. As if a human were updating to a new schema. You don’t want to allow stale, unversioned schema-references littered around the codebase itself; being valid by the time it executes is fine and well functionally, but hell to follow