graphql / graphql-js Goto Github PK
View Code? Open in Web Editor NEWA reference implementation of GraphQL for JavaScript
Home Page: http://graphql.org/graphql-js/
License: MIT License
A reference implementation of GraphQL for JavaScript
Home Page: http://graphql.org/graphql-js/
License: MIT License
It would be awesome if some of the tests can be extracted into a language agnostic format so that we can use them as conformance tests for implementations in other languages.
Something like twitter-text
's conformance tests would be nice: https://github.com/twitter/twitter-text/tree/master/conformance
Currently Scalar types have two methods coerce
and coerceLiteral
. coerceLiteral
is used to create a javascript value from ast, coerce
is used both on variables and on data received from resolve in executors.
Unfortunately that is not enough - variables usually come from some format like json
which wouldn't always support all the new scalar types and most likely will return them as string. On the other hand, eg, databases might return types in javascript format already. Therefore coerce
can't support both variable coercion and execution coercion.
@leebyron suggested that for variable coercion, a new method is added to the Scalars - coerceVariable
.
Hi,
Given the following type language schema:
type Principal {
id: ID!
name: String!
partners: [Partner]
}
type Partner {
id: ID!
name: String!
address: Address
principal: Principal
}
and the following query:
{ Partners {
id name principal {
name id partners {
name principal {
name } } } } }
we see the following requests for data on the backend:
Received request: uid: c5efdde0-7453-4346-81f0-2303a15cc5f3, entity: Partner, filter: all()
Received request: uid: 5c7ad531-baf7-49d1-9b3a-4a10033fba55, entity: Principal, filter: id=1
Received request: uid: e8df54b7-a6d3-47f2-aaa8-7331888cb888, entity: Principal, filter: id=1
Received request: uid: 555e4cea-1cbe-4893-81ce-4c94337e6061, entity: Partner, filter: id=1
Received request: uid: 388165bb-c386-4599-9a2f-85d7cdfda373, entity: Partner, filter: id=2
Received request: uid: 909fd7e9-0921-406c-89d2-881cc827208d, entity: Partner, filter: id=1
Received request: uid: 2462476d-3436-487f-9270-68208e1e5296, entity: Partner, filter: id=2
Received request: uid: bc24de58-25ee-426b-ad77-3994e3dc03ad, entity: Principal, filter: id=1
Received request: uid: 9dea18b2-bc54-4939-b0b5-8d402d8ad1a3, entity: Principal, filter: id=1
Received request: uid: 9935c61b-e386-4fd3-ad36-fb7dff5ed954, entity: Principal, filter: id=1
Received request: uid: 6edd79b0-9333-4741-8bfd-6319909e7c5d, entity: Principal, filter: id=1
[uids are generated per unique call to resolve
].
These repetitious requests came as a surprise given that one of GraphQL's biggest selling points is the elimination of N+1 queries and the introduction of intelligent caching/simplification/reduction etc etc etc
Is this a known issue?
I understand the point given in the examples re- parallel field resolve calls, but generally I would think that it would more common on the back end, certainly at the leaf type level, to be able to resolve all the fields necessary for a given type in one go. Could a type level resolve capability be added to the spec.
Client-side GraphQL should have access to the type IDL we refer to in the spec and any other features that are useful for client-side GraphQL development but have no semantic meaning for execution.
This is a total edge case, but here goes: In my current server implementation I need to support two backends and decide which one to use every time a run a query. So what I did was parametrise all types by the backend they are supposed to use. I made sure there is always a single instance of a type for a particular backend, but the side effect of this is the types don't all get defined before running any queries. They only get defined when resolving an interface type. The original resolveType
looked like this:
new GraphQLInterfaceType({
name: 'Content',
...
resolveType: (value) => {
return (value.item ? ContentV1(backend) : ContentV2(backend));
},
}
Having a fragment defined like this
fragment Basic on Content {
id
title
lastPublished
}
and then running a query containing
somecontentV1 {
items {
... Basic
}
}
somecontentV2 {
items {
... Basic
}
}
breaks trying to resolve the fragment on type Content
. The reason is the possible type names caching in isPossibleType
here:
isPossibleType(type: GraphQLObjectType): boolean {
var possibleTypeNames = this._possibleTypeNames;
if (!possibleTypeNames) {
this._possibleTypeNames = possibleTypeNames =
this.getPossibleTypes().reduce(
(map, possibleType) => ((map[possibleType.name] = true), map),
{}
);
}
return possibleTypeNames[type.name] === true;
}
(https://github.com/graphql/graphql-js/blob/master/src/type/definition.js#L439)
If for instance the first match for a Content
interface is ContentV1
, it will get created, then a fragment gets matched which calls isPossibleType
and caches a single possible type name - ContentV1
. When Content
resolves as ContentV2
, the same thing happens on fragment resolution, but this time, the cache already exists, so although ContentV2
is now defined, the fragment doesn't recognise it as a valid type name. As a result you get an empty object.
I fixed the issue by changing the resolveType
to the following
resolveType: (value) => {
const v1 = ContentV1(backend);
const v2 = ContentV2(backend);
return (value.item ? v1 : v2);
}
that is, instantiating both types eagerly.
I'm not sure this is a common enough case to remove the optimisation, but it should definitely be mentioned somewhere in big bold type that all interface implementations need to be defined at the same time.
Thoughts?
I think it would be more manageable to separate the resolve declaration in the type schema from the resolve implementation code. This could enable the back-end resolve implementations to be produced by independent server-side teams potentially in other languages all together.
Me and @fson at reindex.io have been working on the GraphQL implementation ourselves, ever since it was announced. Super cool stuff!
One issue I've encountered trying the reference implementaion: In our system we have fields in RootQueryType
whose return type is dependent on the type
argument.
query user {
node(type: "User", id: "...") {
// Stuff here is type checked as User
}
node(type: "InvalidType", id: "...") {
// error: InvalidType is not a type
}
node(type: "OtherType", id: "...") {
// Type checked as OtherType
}
}
Is it possible to do such thing with reference implementation? I've found 'resolveType' for interfaces, but that seems to be for having ... on Type
query fragments.
It is possible to just replace those generic fields (we have node
, nodes
, create
and many more like that) with concrete fields like getUser, createUser (and that was our original plan when we started), but we feel that generic fields we ended up with are easier to use.
Thanks!
Okay, I'm still digging into this, and trying to simplify my examples, but it looks like something funky is going on with field resolve behaviour when promises are returned.
Here's example code which demonstrates the behaviour (as well as the results) https://gist.github.com/latentflip/f1c9520ac0d83b5237fc note how in the results, projectPromises differs from projectResults.
Okay, to explain further, the basic setup I have is:
type Org {
id: String
projects: [Project]
}
type Project {
id: String
versions: ProjectVersion
}
type ProjectVersion {
id: String
}
and my root query just returns one org, so the query I'm executing is:
query Foo {
org {
id,
projects {
versions
}
}
}
which should return the org, all it's projects, and all their versions.
However, it seems if my projects.versions
resolve function returns a promise, instead of immediately returning an array, something breaks. To demonstrate, in the actual code linked above, I've got a ProjectReturnType which just returns an array for it's versions and a ProjectPromiseType which returns the same array, but wrapped in a Promise.resolve()
. The latter seems to break the projectPromises
in the response completely, and it just returns {}
.
As I understand it, a resolve function returning a value, or a resolve function returning a promise of that same value, should be exactly equivalent, right?
This could be useful for a tool that would like to generate javascript code based on the GraphQL syntax definition.
If this sound like a good addition to the library I could draft a PR for that.
From the discussion of #44.
According to the spec on scalars under "Result Coercion":
If the server encounters some value that cannot be reasonably coerced
to an Int, then it must raise a field error.
However it seems most examples and tests simply return null instead. What's correct?
For example, I want to validate an email
field.
Should I define my own email scalar type
or just use GraphQLString
and validate the value in the resolve
function?
new GraphQLScalarType({
name: 'Email',
coerce: value => '' + value,
coerceLiteral: ast => ast.kind === Kind.STRING && ast.value.match(/somePattern/) ?
ast.value :
null
});
Similar question for checking the length
of a string. If I have a field that map to a VARCHAR(100)
in a MySQL database, should I create a specific scalar that check for a valid length? Not sure if it's belongs to GraphQL... or if it is a good practise.
Any thoughts?
Thanks
Was just brainstorming how cool it'd be if GraphQL was self-instrumented. Imagine if GraphQL logged every query + resolve timings for each field AND exposed all this data as a built-in type.
On top of this you could build:
The default implementation would be in-memory but easily overridable for any serious install so logs could be persisted.
Thoughts? What does Facebook do for instrumenting/logging GraphQL?
This is potentially a huge advantage to using GraphQL. Monitoring/alerting/auditing is freaking hard and this would standardize a big chunk of it.
Many of my types and many fields on some of my types shouldn't be exposed to some subsets of my users. Is there a way to limit visibility on introspection programmatically?
... rather than waiting for the async result to be produced.
Let's say I have a Database with User entity with a lot of fields:
var Sequelize = require('sequelize');
var sequelize = new Sequelize('sqlite://database.db');
var User = sequelize.define('User', {
name: Sequelize.STRING,
email: Sequelize.STRING,
otherField: Sequelize.STRING,
});
And I have a GraphQL:
var queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
user: {
type: userType,
args: { id: { type: GraphQLID } },
resolve: (_, {id}) => User.findById(id)
},
users: {
type: new GraphQLList(userType),
resolve: (source, args) => {
User.all(); // How to get the requested fields?
//User.all({ attributes: args._requestedFields });
}
},
})
});
And I do a GraphQL query to get name
of all users
curl -s -X POST http://localhost:8080/api/graph -d '{ users { name } }' | jq '.'
I don't want to fetch all the fields from the database. I want to know what fields to fetch...
Is there any way to get a list of fields that were requested in resolve
method?
It would be quite useful to get the rootValue
in resolveType
the same way you get it in field resolvers.
In my case I need to dynamically chose which fetching backend implementation to use and I'm passing it in in the rootValue. The backend also does list filtering by various predicates, one of which is the item type - the backend therefore needs to be able to resolve the item type the same way the interface does.
The natural place for this logic is the backend itself (all backend-specific things sit in one place), but since I only know the right implementation at query run time the type detection logic is now duplicated.
I can imagine other use-cases for the rootValue
in resolveType - e.g. using an authorisation system to resolve to basic or extended type (guess that is kinda contrived) or some sort of user-specified type resolution rules maybe.
Spec: http://facebook.github.io/graphql/#sec-Unions
I find it quite surprising that doing ...on UnionType { fields }
, the response object just contains the fields and nothing about the type of the data being returned.
If we take the example in spec further and add a new type video which also has height and width fields:
type Video {
height: Int
width: Int
}
And then add it to search result union type:
Union SearchResult = Photo | Video | Person
If we had a root query search(query: "foo")
that returned a GraphQLList(SearchResult)
and did something like:
{
search(query: "foo") {
... on Person {
name
}
... on Video {
width
height
}
... on Photo {
width
height
}
}
}
The response could end up looking like this:
{
"data": {
"search": [
{ "name": "John Doe" }, // a Person
{ "width": 1024, "height": 768 }, // a Photo
{ "width": 2560, "height": 1440 } // a Video
]
}
}
How the client is supposed to know what type the results are? I could inspect the returned fields, but that doesn't work when Photo and Video has exactly the same fields. Also it feels kind of hacky.
One solution to this is add a type field for Video, Photo and Person and require the client to request that field also. But is there really a scenario where you don't need this information?
I think what should happen by default is that the value is wrapped with the actual type of each result. For example, the above response would become something like:
{
"data": {
"search": [
{ "Person": { "name": "John Doe" } }, // a Person
{ "Photo": { "width": 1024, "height": 768 } }, // a Photo
{ "Video": { "width": 2560, "height": 1440 } } // a Video
]
}
}
With this response, the client can just loop over the results and do something like this:
if (result.Person) { renderPersonResult(result.Person) }
else if (result.Photo) { renderPhotoResult(result.Photo) }
else if (result.Video) { renderVideoResult(result.Video) }
What do you think?
Hello!
In our system we took GraphQL query and translated it to ReQL (RethinkDB query language) for execution. This allowed us to optimize the query, eg use built-in joins in ReQL instead of querying the database two times. I can see how the similar system can be used for, eg, SQL queries. We also did some further optimizations, like returning only the fields that are requested by GraphQL, reducing the response payload size for tables with many keys.
I see a way to do it graphql-js by manually going through selection sets in resolve, but that feels very clumsy and hacky, as the library does this walking already. Some ways to do it would be to allow children resolve
to modify root or to split collect/resolve/complete steps into independent parts that can be used separately.
Do you think deferred execution and query translation is a good idea? Should we stick to current model and do multiple requests to the database? Is there some solution to that, which I don't see?
Thanks!
utilities/schemaPrinter.js
uses the startsWith string method which Babel does not transform to ES5 code, requiring one to polyfill which I assume is unintended.
How can I get fields requested in external fragment from fieldASTs?
Consider following query
`
query QueryWithFragment {
todo(_id: "55a624bad009804e552eeea8") {
...TextFragment
}
}
fragment TextFragment on Todo {
text
}
`
This query results in following, so there is no way to get those fields without directly parsing query string.
{
"kind": "Field",
"alias": null,
"name": {
"kind": "Name",
"value": "todo",
"loc": {
"start": 27,
"end": 31,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
},
"arguments": [{
"kind": "Argument",
"name": {
"kind": "Name",
"value": "_id",
"loc": {
"start": 32,
"end": 35,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
},
"value": {
"kind": "StringValue",
"value": "55a624bad009804e552eeea8",
"loc": {
"start": 37,
"end": 63,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
},
"loc": {
"start": 32,
"end": 63,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
}],
"directives": [],
"selectionSet": {
"kind": "SelectionSet",
"selections": [{
"kind": "FragmentSpread",
"name": {
"kind": "Name",
"value": "TextFragment",
"loc": {
"start": 76,
"end": 88,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
},
"directives": [],
"loc": {
"start": 73,
"end": 88,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
}],
"loc": {
"start": 65,
"end": 94,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
},
"loc": {
"start": 27,
"end": 94,
"source": {
"body": "\n query UseFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ...TextFragment\n }\n }\n\n fragment TextFragment on Todo {\n text\n }\n",
"name": "GraphQL request"
}
}
}
Now lets take a look in InlineFragment version
`
query QueryWithoutFragment {
todo(_id: "55a624bad009804e552eeea8") {
... on Todo {
text
}
}
}
`
We can easily access requested fields for fragment in selectionSet
{
"kind": "Field",
"alias": null,
"name": {
"kind": "Name",
"value": "todo",
"loc": {
"start": 36,
"end": 40,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"arguments": [{
"kind": "Argument",
"name": {
"kind": "Name",
"value": "_id",
"loc": {
"start": 41,
"end": 44,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"value": {
"kind": "StringValue",
"value": "55a624bad009804e552eeea8",
"loc": {
"start": 46,
"end": 72,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"loc": {
"start": 41,
"end": 72,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
}],
"directives": [],
"selectionSet": {
"kind": "SelectionSet",
"selections": [{
"kind": "InlineFragment",
"typeCondition": {
"kind": "Name",
"value": "Todo",
"loc": {
"start": 89,
"end": 93,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"directives": [],
"selectionSet": {
"kind": "SelectionSet",
"selections": [{
"kind": "Field",
"alias": null,
"name": {
"kind": "Name",
"value": "text",
"loc": {
"start": 104,
"end": 108,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"arguments": [],
"directives": [],
"selectionSet": null,
"loc": {
"start": 104,
"end": 108,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
}],
"loc": {
"start": 94,
"end": 116,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"loc": {
"start": 82,
"end": 116,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
}],
"loc": {
"start": 74,
"end": 122,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
},
"loc": {
"start": 36,
"end": 122,
"source": {
"body": "\n query QueryWithoutFragment {\n todo(_id: \"55a624bad009804e552eeea8\") {\n ... on Todo {\n text\n }\n }\n }\n",
"name": "GraphQL request"
}
}
}
I'm currently working on conversion fieldASTs to MongoDB projections. I've done with InlineFragment. Any thoughts?
There seems to be no way to get errors out of graphql
function and one only gets error title, which can be the dreaded undefined is not a function
deep inside schema or resolve. Would be nice if there'd be a flag to let errors pass through from graphql
function, when they are not validation errors. I'd be willing to implement it if this change makes sense.
Thanks!
I want to build a mutation to modify (let's be original) a ToDo object. My hypothetical ToDo object has three fields: whatToDo
, notes
and assignee
, all of them GraphQLString
s. So I define an InputObject type with all three fields:
ToDoInput = new GraphQLInputObjectType
name: 'ToDoInput'
fields: -> # all of them nullable
whatToDo: type: GraphQLString
notes: type: GraphQLString
assignee: type: GraphQLString
My generic mutation will be like this:
UpdateToDoMutation = new GraphQLObjectType
type: ToDo
args:
id: type: new GraphQLNonNull GraphQLID
attrs: type: ToDoInput
resolve: -> # ...
Now let's assume I want to use this new mutation to do the following: "update the whatToDo
field and set the assignee
field to null
, leaving the rest (notes
) unchanged". I would love to write...
mutation M { // [incorrect GraphQL]
updateToDo(id: 3, attrs: {whatToDo: 'whatever', assignee: null}) { ... }
}
...that is: explicitly including assignee: null
to nullify that attribute, and omitting notes
to leave this attribute as it is. But unfortunately the spec (and @leebyron's Slack remark confirms it) says null
values can only be modeled by leaving the attribute out, colliding with my other semantic needs: omitting an attribute to just not touch it.
Any chance the spec might support null
as a valid literal value? (Otherwise: what other options are there to implement such a generic mutation?).
It would be very useful to add another callback to a field definition which would give you a chance to "post-process" the field value once it has been resolved.
This is useful for collection filtering when using interfaces. The inputs for different types implementing the interface are often different, but the outputs are the same (i.e. the interface structure). The fields on the interface are also likely to be arguments of list fields, e.g.
interface Article {
genre: String
}
type Blog : Article {
genre: String
}
type News : Article {
genre: String
}
type Feed {
items(genre: [String]): [Article]
}
If Blogs
and News
come in in different formats and are coerced into the same structure by their respective types, without the post-processing the filtering is tricky and needs to do the same kind of type detection Article
does to decide on how to resolve the genre
for filtering, which is also already being done by Blog
and News
as well.
Am I missing some obvious way to do this?
Are there any plans to implement the type definition shorthand language parser, so that one could actually write documents describing types instead of using the (slightly verbose) JS notation?
When building a generic resolver (currently i'm trying to build one to map graphql to sequelize) it would be nice to be able to access information about the type of the current field.
Knowing whether or not something is a GraphQLList
of a GraphQLObjectType
or simply just a GraphQLObjectType
will help the resolver in knowing whether to fetch an array of objects or a single object.
source
and root
(the first and third argument) seem to be empty, and ast
(4th arg) only contains a Kind (which is 'Field') and the name value for that field.
I started to work on this graphql implementation in order to integrate it at least partially in our systems. We would like to stay very close to this implementation as much as we can as it may become the first community-supported implementation.
A feature we would need is the ability to wait Promise results when resolving. It doesn't seem that the current implementation support it.
I would like to discuss with you if you are open to support the addition of Promise responses. In this case, I can handle the Pull-request.
So if I were to implement this, I would do it like this:
We can discuss all of that if you wish of course!
It is often useful to associate additional metadata with the schema. I suggest directives similar to those in GraphQL documents to be added to the schema definition language for this purpose.
The most common usecases for them are probably descriptions and deprecation reasons. But like normal GraphQL directives, they also provide an extension point for adding other metadata, such as additonal information about a connection as shown in this example.
interface Node
@doc(description: "Object with an ID")
{
id: ID!
}
interface Connection {
nodes: [Node]
}
type Story implements Node
@doc(description: "Story in the feed")
{
id: ID!
author: User
editor: User
}
type User implements Node
@doc(description: "Story in the feed")
{
id: ID!
name: String
stories: Connection @through(field: "author", ofType: "Story")
username: String @deprecated(reason: "Use name instead")
}
type Query {
story(id: ID!): Story
user(id: ID!): User
}
We are experimenting with generating GraphQL.js schemas from the schema definition language and this syntax would provide a nice way add metadata to the types for that purpose.
I have implemented a proof of concept of this syntax in the schema parser, so I can also open a PR, if this is a good idea.
I've read the specs and saw that mutators are'nt quite well explained, but I have also seen that some sort of implementation seems to be provided.
https://github.com/graphql/graphql-js/blob/master/src/executor/executor.js#L229
Should maybe provide a test example for the mutator or is'nt intentionally provided in the spec yet?
My use case is to implement a generic graphql server and I would like the ability to infer relationship between types from the schema.
To achieve this, I am thinking of using Interfaces as markers to allow the server to provide additional features to decorated types.
Is a valid use of Interfaces or is it more of a hack.
Hi,
First of all, I´d like to thank you for the awesome job you have done with the spec and this reference implementation. It took only couple of hours to build a GraphQL "proxy" server by generating GraphQL schema from a preexisting JSON schema definition we had for our REST API and I'm already experiencing the benefits.
The only question I have is this; We have some abstract field types in our api. For example some responses may contain user supplied JSON metadata. This means I'm unable to define the actual fields and types for the data. Currently I'm using an ugly way to handle these fields by creating a scalar type and using that for the metadata fields.
var GraphQLAnything = new GraphQLScalarType({
name: 'Anything',
coerce: function (value) {
return value;
},
coerceLiteral: function (ast) {
return ast.value;
}
});
This works as desired (I'm able to receive the data in correct form) but defining something like this as a scalar feels wrong in so many levels. Especially as the spec says that "Scalars cannot have fields.". Is there a correct way to handle these type of values?
Thanks!
I expect the following query on the star wars schema
{
__type(name: "Character") {
fields { name }
}
}
to have the following output
{
__type: {
fields: [
{ name: "__typename" },
{ name: "id" },
{ name: "name" },
{ name: "friends" },
{ name: "apearsIn" }
]
}
}
but the __typename
field is missing because it seems to be "dynamically evaluated". Shouldn't it be part of the list of available fields?
Also, in my opinion, querying for the fields of the root query object should also include the __schema
and __type
fields.
The top level tests describes a pretty simple schema, but it doesn't go into input objects or unions. A more comprehensive example would be useful.
When a Float field is added to type definition, the materializer (buildASTSchema
) breaks down with Error: Type Float not found in document
. Adding a float field to HelloScalars test confirms the issue.
Patch is simple, one-line tweak to getTypeDefProducer function in utilities/buildASTSchema.js to add Float
to innerTypeMap
map, as follows:
function getTypeDefProducer() {
var innerTypeMap = {
String: GraphQLString,
Int: GraphQLInt,
++++ Float: GraphQLFloat,
Boolean: GraphQLBoolean,
ID: GraphQLID,
};
With this, the new HelloScalars test passes, I'll submit a PR in a sec (updated test + patch).
It would be nice if github activity was automatically pushed to slack so that users can track activity in one place.
Would be great to see some mutation
queries.
All, great work all around on graphql reference implementation, it's incredibly helpful.
I have been using the schema DSL parser and buildASTSchema to materialize the schema and noticed a small bug in utilities/buildASTSchema. Specifically, when both queryTypeName and mutationTypeName are passed to the buildASTSchema, the schema is not constructed correctly - query is missing.
I traced the bug down to the lines 150-157 of utilities/buildASTSchema, where if mutationTypeName is passed, schema object is constructed with the queryTypeName string instead of queryType object:
if (isNullish(mutationTypeName)) {
schema = new GraphQLSchema({query: queryType});
} else {
schema = new GraphQLSchema({
query: queryTypeName,
mutation: produceTypeDef(astMap[mutationTypeName]),
});
}
This should fix it -
if (isNullish(mutationTypeName)) {
schema = new GraphQLSchema({query: queryType});
} else {
schema = new GraphQLSchema({
query: queryType,
mutation: produceTypeDef(astMap[mutationTypeName]),
});
}
Note that this slipped since buildASTSchema tests don't include a case when both mutation and query are passed. I am happy to fix this, add a test and submit a PR, if welcome.
Since the transformations applied before exporting the package to npm strips the flow annotations but not the comments, a lot of flow errors arise after a npm install graphql
.
Here's some of them:
/Users/rricard/src/github.com/rricard/td-foundation/lib/td-mirror/node_modules/graphql/lib/error/index.js:37:25,31: parameter message
Missing annotation
/Users/rricard/src/github.com/rricard/td-foundation/lib/td-mirror/node_modules/graphql/lib/error/index.js:39:3,7: parameter nodes
Missing annotation
/Users/rricard/src/github.com/rricard/td-foundation/lib/td-mirror/node_modules/graphql/lib/error/index.js:39:10,14: parameter stack
Missing annotation
/Users/rricard/src/github.com/rricard/td-foundation/lib/td-mirror/node_modules/graphql/lib/error/index.js:73:23,27: parameter error
Missing annotation
/Users/rricard/src/github.com/rricard/td-foundation/lib/td-mirror/node_modules/graphql/lib/error/index.js:73:30,34: parameter nodes
Missing annotation
...
... 121 more errors (only 50 out of 171 errors displayed)
To see all errors, re-run Flow with --show-all-errors
One solution would be to strip the /* @flow */
comments from the npm package. But we would lose all of the useful information contained inside those annotations. If we had a transform able to put the annotations in a comment, that would be much better...
Anyway, I'm open to discuss the best way to fix this so I can start working on a pull-request and/or a new transform for flow annotations!
Query:
{
curatedList {
...on Program {
title(lang: "fi")
}
...on Article {
title
}
}
}
Error:
Fields title conflict because they have differing arguments.
Should it really work like that, or is this a bug?
Article and Program are both members of union type Content
It would be nice to define the schema definition in a language agnostic way e.g. xml so that the schema could be shifted between graphQL implementations. This could also one to use more mature implementations in the meantime.
Name is context-sensitive in that, for example, the string "on" is a Name
unless it appears in a place in the grammar that requires on specifically (e.g., right after an ellipsis, as in InlineFragment
, or two tokens after fragment, as in FragmentDefinition
). Naive application of tools like flex and bison seems likely to produce a system that doesn't allow apparent "keywords" like on
/fragment
/query
/mutation
to be used as Name
s (e.g., as the names of fields). We should add test cases in src/language/__tests__/parser.js
that demonstrate that these are legal Names.
Vectors in graph could reference to each other in any direction.
So I should be able to use GraphQL type before it's implementation.
I don't found a possibility to do this right now. Am I right?
const Good = new GraphQLObjectType({
name: 'Good',
fields: {
title: {type: GraphQLString}
}
})
const Product = new GraphQLUnionType({
name: 'Product',
types: [Good],
resolveType(root) {
return Good
}
})
{ errors:
[ { message: 'Cannot query field title on Product',
locations: [ { line: 14, column: 13 } ] } ] }
This is a question for practice rather than a problem.
resolve
methods take a root object as the 3rd argument, and so does the graphql method.
Is root
meant as the way to pass around context information (like the session if wanting to implement viewer
from the relay video examples)?
Can you add a changelog with description of new features usage. This commit looks like we can now use GraphQL on the client, but there is now good description on how to do it right.
GraphQLSchema does not expose the use of custom directives. Based on the spec, the @skip
and @include
directives are required and appears to allow for custom directives.
The GraphQLSchemaConfig
type doesn't allow a list of directives, and neither does the GraphQLSchema
allow directives through the constructor, but it is possible to set the _directives
prop on the GraphQLSchema
type, so it's technically possible but not exposed.
I might be thinking about this wrong, but it feels really useful to be able to define a union of interfaces as a type. Alternatively, it would be nice to be able to supply multiple interfaces as a field type.
What I'm thinking of as a use case is a sort of type composition. Let's say I have an interface
interface Image {
src: String
}
which represents an image I can display. Some images are stand-alone and I can link to them as a page, but other things share that capability. So I have another interface
interface Linkable {
url: String
}
Now let's say that all users have profile pictures which are linkable. I'd like to be able to declare something like this
type User {
profilePicture: Image + Linkable
}
When resolving such type, the only requirement is for the interfaces not to contain the same attributes. From there it should be entirely possible to find the defining interface for each attribute and then the implementing type based on interface type resolution.
Are there any plans for supporting this kind of thing or am I missing something that makes the implementation really hard or impossible?
This is not really as much a problem as a question about practices. Playing with GraphQL I realised that argument resolutions rely on types always getting the same data structure from the parent resolver (unless you want to branch the logic in them).
Is there any clever way to ensure this? So for instance wherever I define an attribute of the Image
type, I can make sure a resolver for that attribute eventually returns a data structure which attribute resolvers on Image
can handle.
The coerce
function for the integers is defined as
export var GraphQLInt = new GraphQLScalarType({
name: 'Int',
coerce(value) {
var num = +value;
return num === num && num <= MAX_INT && num >= MIN_INT ? num | 0 : null;
},
coerceLiteral(ast) {
if (ast.kind === Kind.INT) {
var num = parseInt(ast.value, 10);
if (num <= MAX_INT && num >= MIN_INT) {
return num;
}
}
}
});
Which means that if a number does not fit the 32 bits, then the significant bits will be truncated.
Which is generally a not expected behaviour, since the coercion must either produce a valid result, or a null
.
References:
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.