GraphQL Types II: The Wrath of String!

Jason Eden
6 min readOct 12, 2021

But wait! There’s More!

In my last GraphQL post I tried to clearly define the three core types of a GraphQL schema types: object, scalar, and enum. This time, I will look at extensions and modifications to the core types that further increase the flexibility of GraphQL, even if they do at times continue to suffer from a lack of clarity in the documentation.

The NonNull Designation

While there are just the three core types of schema types, there are also type modifiers that can be deployed to affect their behavior. One of the things I glossed over last time was the exclamation point in the GraphQL example.

STRIIIIIIIIIIIIIIIIIIIIIINNNNNNNNNNNNNG!!

The exclamation point in GraphQL SDL simply means that the thing to which it is attached cannot contain a null value. So in the Character object type, the name scalar type has two requirements: it must be a string data type, **and** because of the exclamation point, the value cannot be null.

In Graphene, the same logic can either be implemented by nesting the data type inside a NonNull function, or by setting a flag called “required” to true. The SDL above can be implemented in Graphene Python by either of the following:

…or…

Lists and NonNull Lists vs. NonNull-Lists vs. NonNull-NonNull-Lists

Because overlapping terminology and concepts aren’t already enough of an issue for GraphQL documentation…

Lists are another type of type modifier. They indicate that an array, rather than a single value, will be returned. In GraphQL SDL lists are designated via square brackets “[ ]” around another type which contains one or more responses. To step back and reference the example provided, Episodes might be an object type defined elsewhere in the schema. By specifying the data type to be returned is a list of all applicable episodes for the given character using [Episodes], you allow multiple responses to a single query.

Here is one point where the Graphene and GraphQL documentation diverge. In the GraphQL SDL, you specify the list designation around the object type you are going to use as a response. In Graphene Python syntax, however, apparently you specify the thing to be returned is a list, but you specify the data type to be returned once again, rather than a separate GraphQL type (or Graphene class). For example, the documentation provides the following example for defining a list to be returned:

Note the lack of an object definition for the output of appears_in. Instead, the variable (scalar type) definition simply indicates that a list of strings is to be returned. It is unclear at this point whether an object type for appears_in would need to be defined elsewhere, or if Graphene simply retrieves and returns multiple items without this needing to be explicitly defined in the schema. A third alternative is the Graphene documentation may be in error.

My suspicion is that the Graphene documentation I am referencing may be in error, and indeed you would need to reference another type in a list, rather than specifying the data type (such as String). Later on we will see a list that contains a lambda object and refers to another type, which may be a clue, or may simply be an alternative way to implement. At this point, I will put this question on hold until I have connected a functional back-end system against which to test multiple options.

NonNull List Variations

You can combine type modifiers to get specific results. For example, in GraphQL SDL [Episodes]! would indicate that the list response cannot be null. You could also use [Episodes!] (note the subtle difference in placement of the “!”) to specify that none of the responses in the array could be null, although the list itself could be. For example, a response array of “a, b, null, d, e” would be acceptable for [Episodes]!, since the array itself is not null, but would not be acceptable for [Episodes!] because of the null value in the array itself.

In Graphene, you can simply nest designations in functions to achieve the desired result. Thus, one way to specify a list equivalent to [Episodes!] would be the following:

Presumably, the equivalent of [Episodes]! then would be something like the following (although this is not listed in the Graphene documentation, so I will need to experiment to see if this works as expected):

appears_in = graphene.NonNull(graphene.List(graphene.String))

If you want to specify that both the list as well as all elements of the array returned were not null, you would code the schema as follows: [Episodes!]!

Again, a presumed Graphene equivalent would probably be:

appears_in = graphene.NonNull(graphene.List(graphene.String(required=True)))

Or you might wrap the NonNull modifier around both the list and the string type designation to get the same effect. Again, further exploration is required.

Interfaces

Interfaces are yet another kind of type, or rather, extension of types. An interface allows you to define a core set of features for a sub-object type that must then be part of the definition for a broader type. The GraphQL SDL example looks like this:

STRIIIIIIIIIIIIIIIIIIIIIINNNNNNNNNNNNNG!!

Then if you want to implement this interface, in GraphQL SDL you need to make sure all the types defined in the interface are included in the broader object definition. Again, the example they give helps sharpen this definition:

Is it the Droid you’re looking for?

Note that both the Human and Droid object types implement the Character interface. Thus, when defining Droid and Human, you have to ensure the id, name, friends, and appearsIn definitions are present and match the interface, or else an error will occur on the query. However, the Human object type extends the interface with starships and totalCredits, whereas Droid extends by primaryFunction.

When reading through the GraphQL documentation on this, I failed to comprehend the point of an interface, if using a schema-first approach. Indeed, you could simply define Human and Droid without making reference to the “implements Character” and they would work exactly the same way.

This was another example of where the code-first approach Graphene uses made a lot more sense to me. The interface definition is just another Python class:

Note the list definition with lambda: Character. I haven’t yet run across where this is fully explained.

But then, once defined, when implementing the interface, there is no need to retype the variable names or definitions.

Those WERE the Droids I was looking for!

Note here that you simply reference that you are implementing an interface via class Meta: and then specify the list of interfaces to reference. After that, you simply provide the unique scalar types for this object type and you’re done. This code makes the implementation of an interface construct make a lot more sense, and the output is exactly what GraphQL expects from the SDL:

I feel like I’ve mixed my movie metaphors somewhere along the line.

This wraps up the explanations and examples of what I am now thinking of as GraphQL “structural” schema types and modifiers. We’re not done typing about types yet though — there are a whole set of “functional” schema types that actually define what you can do — how you interact — with GraphQL. There’s a lot more fun to be had poking fun at types, but I suspect once I’m finished and have at least some idea of what it is I’m going to try to accomplish, the step to go from defining schemas to actually executing a query against a back-end data source is going to be a big one. Stay tuned!

Sources:

https://docs.graphene-python.org/en/latest/

https://graphql.org/learn/schema/

--

--

Jason Eden

Data Science & Cloud nerd with a passion for making complex topics easier to understand. All writings and associated errors are my own doing, not work-related.