When I use connection_type it creates edges and node as nullable fields.
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "AwsAccountOrOnboardingEdge",
"ofType": null
}
},
...
},
Does this make sense? I don't see why these should be null. Maybe the edges does, not sure.
At least shouldn't node be NOT_NULLABLE?
It looks like edges is nullable according to the spec: https://facebook.github.io/relay/graphql/connections.htm#sec-Edges
But node may be a non-null type: https://facebook.github.io/relay/graphql/connections.htm#sec-Node
I'm open to supporting non-null node fields, but I don't think we should change the default behavior.
FWIW the vast majority of our connections use non-null nodes. In fact any field we create that is a list defaults to the inner wrapped element being non-null unless otherwise specified.
For a bit more context. We are using Elm for our front end. We started using a library that generates types from our graphql schema. So at the moment for a connection we get something like:
List (Maybe { node = Maybe Thing} )
^ edge ^ node
Having to deal with these nullables in the FE is harder than it should be. We would like to be able to specify a connect_type where nothing is null. So we can end up with:
List { node = Thing }
Thanks
This is not an issue just with Elm but also TypeScript/Flow or any other type system.
There's a similar discussion for graphql-relay-js. Specifically, it reiterates that edges are always nullable while nodes can be non-null, and that nullability is required in case of an error.
I originally came here to +1 for making the edges non-null but now I'm not so sure. As for nodes, I think those should still be non-nullable.
For those looking to make everything non-null in their app:
First, define a BaseConnection that makes edges and nodes (if you use them) non-null.
class Types::BaseConnection < GraphQL::Types::Relay::BaseConnection
def self.edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: true)
# Set this connection's graphql name
node_type_name = node_type.graphql_name
@node_type = node_type
@edge_type = edge_type_class
field :edges, [edge_type_class],
null: false,
description: "A list of edges.",
method: :edge_nodes,
edge_class: edge_class
field :nodes, [node_type],
null: false,
description: "A list of nodes." if nodes_field
description("The connection type for #{node_type_name}.")
end
end
Then define a BaseEdge that makes each node non-null.
class Types::BaseEdge < GraphQL::Types::Relay::BaseEdge
class << self
# Get or set the Object type that this edge wraps.
#
# @param node_type [Class] A `Schema::Object` subclass
def node_type(node_type = nil, null: false)
if node_type
@node_type = node_type
field :node, node_type, null: null, description: "The item at the end of the edge."
end
@node_type
end
end
end
And finally hook them up in your BaseObject:
class Types::BaseObject < GraphQL::Types::Relay::BaseObject
connection_type_class Types::BaseConnection
edge_type_class Types::BaseEdge
end
Note: Since 1.9.5, GraphQL::Types::Relay::BaseEdge accepts the null param in the node_type method and defaults it to true, which means you can make your node null in each custom edge without having to provide a Types::BaseEdge of your own.
class Types::MyEdge < GraphQL::Types::Relay::BaseEdge
node_type(MyType, null: false)
end
Still, to default to false, implement your Types::BaseEdge as shown above.
While I think @petrbela 's solution works, I would rather have official support for this before using it. That being said, there probably needs to be liberal warnings about the tradeoffs that you are making when using non-null types [1], namely:
[1] - https://medium.com/@calebmer/when-to-use-graphql-non-null-fields-4059337f6fc8
I don't have plans to add more support in this area. The built-in classes provide inspiration for your own connection types, which aren't too hard to build, and you could even extend those built-ins. Please let me know if you try it and run into trouble!
Most helpful comment
For those looking to make everything non-null in their app:
First, define a
BaseConnectionthat makesedgesandnodes(if you use them) non-null.Then define a
BaseEdgethat makes eachnodenon-null.And finally hook them up in your
BaseObject:Note: Since 1.9.5,
GraphQL::Types::Relay::BaseEdgeaccepts thenullparam in thenode_typemethod and defaults it totrue, which means you can make yournodenull in each custom edge without having to provide aTypes::BaseEdgeof your own.Still, to default to
false, implement yourTypes::BaseEdgeas shown above.