jlouis / graphql-erlang Goto Github PK
View Code? Open in Web Editor NEWGraphQL implementation in Erlang.
License: Other
GraphQL implementation in Erlang.
License: Other
This task depends on Issue #107. Once that is done, then this is trivial to satisfy. You walk the document, and build a union set over the variables in it. A fragment contains a type signature which transitively knows about its variable uses.
Once the full set is created, you can use it to subtract from the set of variables. If that set becomes the empty set, then every variable has at least one use.
This is wrong because it messes with the object. They become null as if the field was non_null, yet that might not be the case.
Commit 6bdc1b6 introduces the variants/1
function in the graphql_schema_parse
, which assings a numeric value to each enum variant, starting with 0 and incrementing by 1 for each consecutive variant. This reduces boilerplate code dramatically, but unfortunately, this setup:
.graphql
schema file importantCurrently, this affects moose, as moose needs to be able to distinguish and search among different authentication method representation, that are parametrized by the AuthenticationMethodType
enum. Prior to the new way of doing things(TM), variant values were explicitly defined and could be
canonicalized as this example shows
{enum, { ...,
values => #{
'AUTHENTICATION_METHOD_FACEBOOK' =>
#{ value => gryphon_person:authentication_method_type(facebook),
description => "Authentication method facilitated by Facebook."
},
...
}
}
}
@jlouis Can we come up with a solution allowing variant representation values to be determined or looked up outside of the graphql?
Hi,
this might seem a little counter-intuitive at first, but hear me out:
Using graphql-erlang from Elixir is currently slightly pesky, since one has to either traverse the whole tree/list of results to replace null
with nil
or nastily patch JSON encoding to treat null
as null
instead of the default Atom -> binary "null"
.
I have been going back and forth with some hacky solutions, but thought maybe its worth having this discussion upstream here.
I am happy to help by sending in a PR that is currently representing a project-wide rename of the null
-Atom to nil
. It would give the folks over in Elixir land instant compatibility to bind to this excellent library.
Here is something to have a laugh about while pondering. (It's all ALGOL W's fault.)
Variable uses should propagate into Fragments as well. This is related to #70 and should probably be handled in the same patch. Many of the things can be pushed around in the type checker if you start building "function specifications" for fragments.
Hi everyone,
I am running against the latest master version.
And I am seeing strange encoding problems when querying the default responses with GraphiQL.
For demonstration purposes I used your graphql-erlang-tutorial
application.
So this is the response header that cowboy sends for the introspection query.
It states that content will be utf-8 encoded:
HTTP/1.1 200 OK
server: Cowboy
date: Tue, 19 Dec 2017 18:44:19 GMT
content-encoding: gzip
content-length: 4069
content-type: application/json; charset=utf-8
vary: accept
snip
But inside the response, documentation annotations can be found that have encoding issues.
Here is one example of the introspection of the SCALAR type Float
:
{"description":"Floating point values, IEEE 754, but not �infty, nor NaN","enumValues":null,"fields":null,"inputFields":null,"interfaces":null,"kind":"SCALAR","name":"Float","possibleTypes":null}
When looking up the source for this string, I found this in src/graphql_builtins.erl:15
:
description => "Floating point values, IEEE 754, but not ±infty, nor NaN" }},
So there is definitely something fishy going on. Unfortunately I do not know how to fix this quickly.
I think maybe there is an encoding issue when fetching graphql-erlang
as a dependency (it definitely happens on a vanilla graphql-erlang-tutorial application).
This issue prevents some clients, and also my server, to render introspection queries/results.
We used to be able to send auxiliary data back from a resolver like so:
{ok, Result, [AuxiliaryData]}
This data would show up under the aux
field in the query result map, but this functionality seems to be lost in a recent commit. We need to:
Consider the following query:
mutation C($n : String) { createUser(input:{name: $n}) { user { id name }}}
This erroneously makes a call like the following:
#{<<"name">> => {var,{name,34,<<"n">>}}}
which should have been expanded. To fix this, we need to understand what is happening in the expansion system inside the type checker.
We need to have a place where we track validations. We begin this work by building the complete list, then mark what we already have covered. Things not covered are pulled into their own issues for further tracking.
From the Oct2016 specification:
Publish this package (and the tutorial) on hex.pm.
Handle these cases
Handle this case.
(NOTE: I think this is already handled now in the type checker).
Currently, default values are not coerced. They should be.
Handle these cases
The following query will require 1 SQL query to get the books and N queries to get each author.
{
books(genre: "comedy") {
title
author {
name
}
}
}
Is there a way to make only 1 or 2 SQL queries with graphql-erlng?
Suppose we have a fragment
fragment M on Monster {
...
hitPoints(above: $foo)
...
}
Then this fragment is valid as a spread in any query Q
which defines
query Q($foo : Int) { ... }
But not in a query
query Q($foo: String) { ... }
Also, note that if we have another fragment
fragment R on Room {
description(language: $foo)
}
Then if language : Locale
you are not allowed to mix fragments M
and R
in the same query.
M
refers to a subfragment I on Iventory
and that fragment refers to $bar
, then M
also refers to $bar
.The reason this has been held off for a while is that it isn't that simple to implement:
fragment
. This allows us to ask if a fragment "fits" when it is called by a fragment spread.Our (experimental) concurrent execution currently waits 750ms for some event to happen. This is arbitrarily chosen and if the deadline is met, we fail the query. We'd like for each defer
statement to tell the engine what it expects is the deadline. This will allow us to manage deadlines in the system and run with higher deadlines.
This issue tracks what there is to be done in order to solve this problem.
{error, timeout}
as the response result and feed that to the closure. It will then resolve itself properly, but as if an error occurred.Add the possibility to split the graph schema in diferentes files, that files must be joined and evaluated as a singe schema file.
As @jlouis suggested , we could use a directive at top of file like package my-graphql-erlang
, for example where every file that references that package will be into my-graphql-erlang.graphql
A fragment spread is ...Frag
. They are written as fragment Frag on Dog { ... }
. The fragment has a type, (in this case Dog
) and the context in which the spread occurs has a type (not shown here). For a query to be sensible, they must match. In short, there must be a way for the fragment to eventually match. Otherwise the fragment is wrong.
There is code for this in the system already. It would be obvious to check this in the type checking phase: look up the fragment type and expand it into its possible types (unions, interfaces, objects). Do the same with the spread and look for a valid overlap.
However, it isn't clear that this is currently handled, so:
The system must reject e.g.,
{
field(arg: { field: true, field: false })
}
Because it isn't unique. This belongs as a check in type-checking when checking input objects, if it is not already there.
Handle this case
The schema snippets below sets the stage
input I {
nonNull: String!
list: [String]
}
type Mutation {
m(input: I!): ...
}
GraphQL crashes with runtime error {case_clause, null}
in graphql_execute.erl
when attempting to perform this mutation:
mutation M {
m(input: {nonNull: "non-nullable string"}) {
...
}
}
That was a handful to type.
Basically, given a named query:
query FindSomething($input: Input!) {
find(input: $input)
}
$input
contains a type error (e.g: negative number for a uint type).
operationName
is not given by the client and following graphql-erlang-tutorial, it is set to undefined
.
Given this query, graphql will crash with:
#{class => error,
error => {case_clause,{undefined}},
module => my_web_handler_module,
stacktrace =>
[{graphql_err,'-path/1-F/1-0-',1,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_err.erl"},
{line,43}]},
{graphql_err,'-path/1-lc$^2/1-2-',2,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_err.erl"},
{line,60}]},
{graphql_err,path,1,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_err.erl"},
{line,60}]},
{graphql_err,mk,3,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_err.erl"},
{line,20}]},
{graphql_err,abort,3,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_err.erl"},
{line,16}]},
{graphql_type_check,check_input_object_fields,4,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_type_check.erl"},
{line,232}]},
{graphql_type_check,'-tc_params/3-fun-0-',4,
[{file,"/home/bullno1/Projects/nm-exchange-api/_build/default/lib/graphql/src/graphql_type_check.erl"},
{line,131}]},
{lists,foldl,3,[{file,"lists.erl"},{line,1263}]}]}
Which I guess is while it's trying to build the error path, hence the undefined
case clause.
After I give operationName
a correct value, graphql reports the type error correctly without crashing.
GraphQL commit: 135657f745254198f3d07e35fd3a63623144b119
A fairly straightforward case. We already have a uniqueness checker in the code base, we just have to call it before we proceed. So I think this task is among the low-hanging fruit.
Not an issue per se, I'm just not sure how to do batch loading in graphql-erlang.
I'm trying to use this optimization: dataloader to batch up individual queries into a big one.
Basically, in dataloader, a call to dataloader.load(id)
will return a promise. At the "next tick", all ids will be sent in a single batch query to save round trip time and all promises will be resolved.
While deferring is already possible in graphql-erlang
, "joining" is not as the concept of a "next tick" doesn't make much sense in Erlang.
Is it possible to register a callback which will be called here: https://github.com/shopgun/graphql-erlang/blob/develop/src/graphql_execute.erl#L912? It can inform the batch loader to start sending.
Alternatively, is there a better way to implement batch loading?
The system must reject the following query, which has a fragment which is never used in the system.
fragment nameFragment on Dog { # unused
name
}
{
dog {
name
}
}
Handle this case
There is a test case for this one, but we are currently skipping the test case. Figure out why.
Handle this case
Not sure if this is a bug or a feature.
Given the schema:
type Query {
articles(includeDeleted: Boolean = false): [Article]
}
And the query:
query ListArticles($includeDeleted: Boolean) {
articles(includeDeleted: $includeDeleted) { title }
}
Calling the query without providing $includeDeleted
will result in null
being passed into articles
( i.e: articles(includeDeleted: null
) while includeDeleted
was specified to default to false
. Changing the above query to:
query ListArticles($includeDeleted: Boolean = false) {
articles(includeDeleted: $includeDeleted) { title }
}
will achieve the desired result but that's a repetition of default value.
GraphQL commit: 135657f745254198f3d07e35fd3a63623144b119
I am exploring using graphql on an embedded device, and the dependence on lager pulls in approximately 2MB of .beam (lager->goldrush->compiler), whereas graphql itself is only 0.38MB.
I see lager is used in only 4 places. Is depending on lager crucial here? I've never used lager before so I don't know what it is bringing to the table.
Maybe you could tag the 0.8.0 version? Is there any reason why not?
The validator for this is not yet implemented (it is somewhat contrived and complex). This issues tracks the field selector.
Rather than supplying a query document each time, support caching a query handle on the server side and let queries refer to this in the future. This speeds up queries as we can skip a good part of the parsing and validation each time.
Given this invalid annotation:
# Notice the uppercase "Text"
+description(Text: "Fail")
This makes graphql:load_schema
fails with {error, {schema_canonicalize, {error, badarg}}}
which does not help the user to track down the error.
I'm not sure what's the right fix for this one.
In operations you can have variables $var1, $var2
and so on. When they are used, transitively, it is important that they are used in ways that doesn't break the type system. We are currently doing some of the checking work, but not the transitive follows into fragments. This has to be done.
I think this one is handled as well, but it does require a test in the validation suite.
The current system resolves the error but makes the error propagate too far. It should turn that error into a null value. This is a rather simple fix, which should improve error handling by quite a lot in the responses.
I found the problem toying with the star wars tutorial yesterday.
Currently it is only possible to serve one GraphQL schema on an Erlang node. It would be useful to be able to run multiple GraphQL schemas on a single node for a couple of reasons:
This would require all the internal lookups to be name-spaced.
If we return an integer in a position which expects a float, we currently do no conversion. But it is possible to just convert the integer in this case. Consider this.
Handle these cases
A schema with missing mutation and query types will result in the error schema_not_found
, even though the schema file does exist. We should consider a better error for this scenario.
Defining a query node like this will crash the GraphQL server:
type Query {
# …
nodes(): [Node]!
}
This works:
type Query {
# …
nodes: [Node]!
}
Is this valid or should it error with a reason?
Execution of a test such as
query { hello }
Currently fails to get through the parser. This is wrong and should be remedied. It is currently not known when this error came into existence.
The bug is clearly in the parser since the parser rejects the above document. But it shouldn't reject the above document as it is valid. The document
{ hello }
is accepted and this could be a hint as to what is going on here.
We need to investigate this. There are a couple of places where you cannot expand __typename
as you should because the introspection part reports it as an invalid field. This is obviously a bug.
Currently, there is a test in the enum SUITE, no_correct_internal_value, which is there to test we correctly handle output rules for enumerated values. We currently don't.
The fix is in the execution layer. When you return from a resolver of enum type, we must check that the returned value indeed matches the valid possible enum values. Otherwise, this is an error. Also, while here, we must lock down what the correct return value for an enum type is in the case where you are using the default resolver. Before this has gone in, we cannot document how enum resolution works.
A query such as
query ($n : Int) {
grabStuff(size: $n) {
id
}
}
Is produced by Apollo. It fails because we expect something like query N(...) { ... }
where the query has a name. Check:
Is there any reason why subscription is not supported? All the codes are already there and it seems to be intentionally ignored in graphql_execute
and graphql_schema_canonicalize
.
Would a trivial pull request to enable it to have identical semantics to query be accepted? Or did I overlook something non-obvious with subscription?
Currently when a node resolve to no data we return {ok, null}
; this is fine for an Erlang and JSON context, but if we want to use another output format, or use graphql-erlang as an interface to another system that require something else (like {ok, undefined}
) we could benefit from making this configurable.
This will have to happen when the graphql-execute finalise a value.
Annotating a field of an enum in a schema will result in a crash when evaluating the graphql schema:
How to reproduce:
Add something like this to the schema:
enum Status {
+description(text: "This will make the parser crash")
SUCCESS
FAILURE
}
Reload the graphql schema in an interface like graphiql.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.