A walk in GraphQL — Input Objects and Enums— Day 3

8 articles to learn GraphQL incrementally, keeping the implementation agnostic spirit of the SDL

Javier Valderrama
5 min readMay 21, 2021

Input Object

Simple operation arguments are relatively easy to define and control and scale as we saw on Day 02 but what if we need to pass along more than a simple Scalar?

What if we need to:

  • pass along an object
  • make sure all props belong to a specific type
  • control the nullability for each prop and for the object itself
  • reuse the same input and its validations across multiple operations
  • add annotations to both the object and each individual prop

The SDL specifies a type for this case and states the following:

Some kinds of types, like Scalar and Enum types, can be used as both input types and output types; other kinds types can only be used in one or the other. Input Object types can only be used as input types. Object, Interface, and Union types can only be used as output types.

Source: GraphQL spec (June 2018) — Input and Output Types

Now imagine you want to always be able to filter a certain Object Type by more than 1 field … let’s say 3

(⊙_⊙’) that’s absurd!!

And we’re talking about 14 lines of type definitions!!! Can you imagine scaling and maintaining this on a real world application?

This is one of the cases where Input Object Type shines.

Note that using the name input for the argument and using the name InputCharacter for the type definition is completely arbitrary, you can use whatever the team agrees to use.

Here’s a sample query you could request against the server for the type definition above.

and here the response

Fields validation

If you try to use an unknown field for the Input Object you’ll have an error from the server (and a warning from your preferred dev tool if you have one)

Response

And — as any type validation — the server will cry if a field value doesn’t match the defined type.

Non-nullable fields

but it’ll make it mandatory on every place you use it as input, otherwise it’ll throw an error like this: "Field InputCharacter.skill of required type String! was not provided."Use it wisely

Extending Input Objects?

Unfortunately you cannot do something like input InputCharacter extends Character or input InputCharacter2 extends InputCharacter1 … you’ll have to explicitly define it yourself. Nothing stops you from creating it dynamically with your preferred programming language, in that case it’s suggested to generate a static output of your type definitions so you can leverage the development tool’s static code analysis (local or remote).

Nested Input Objects

Why is that? Remember? Because “Object, Interface, and Union types can only be used as output types.

A note on reusing Input Objects

Input Objects are perfect for reuse, but it’s in your hands to determine “if, when and how” to reuse them. It’s perfectly fine to define an Input Object without reusing it!!

  • Operations of the same type may evolve differently, reusing the same input might become a stick in the wheel.
  • Avoid reusing the same Input Object for different operation types (query, mutation). They’re likely to have different requirements for non-nullable fields

Enum

This is a particularly interesting type that represents a finite set of values. Its values are represented as unquoted names (usually defined in all caps) that must be valid and unique within the set and there must be at least 1 value. They are (like Scalar Types) the leaf values in GraphQL.

On the sample query defined here we could pass any arbitrary value to the kind field (e.g input: { kind: "whatever", homeland: "The Shire", skill: "the ringy thing" }) without problems, the query can be performed and no errors will be thrown, probably returning no records. But, in the following example, we’ll add an enum definition forcing the value to be one of the set (or null in this case) and throw an error if it’s not.

Our query should be as follow

A secondary — but not less important — advantage of enums is that now the value is not only validated against your typedef and it’s auto-completed in your preferred dev tools, but it’s also abstracted! Means the client is no longer dealing with actual values but with abstracted representations which is more secure and scalable.

Language specific support for enums and internal values

The language specific implementation of enums will affect how you will have to handle the discrepancies on your side, and sometimes a backend forces a different value for an enum internally as opposite to the one in the public API.

In our example we have that discrepancy because the backend representation (internal representation) of the kind field is half-elven which doesn’t correspond to a valid name, so we used HALF_ELVEN.

The strategy to solve these cases will depend on the language and the server app you’re using.

E.g. Apollo Server allows the addition of custom values to enums as shown below.

Exercise

For a given datasource (abstracted as json here) containing n rows of skills and n rows of persons we provided a sample implementation of a GraphQL server for each technology containing:

  • a server app
  • a schema
  • a resolver map
  • an entity model
  • a db abstraction

The code contains the solution for previous exercises so you can have a starting point example.

Exercise requirements

  • Update the type definition and the resolvers to be be able to perform the query operations listed below (can you provide other sample queries when your code is completed?).
  • Discuss with someone else which would be the best way to use Input Objects and Enums and try some. (there’s always a tricky question)

Operations list

Provide the necessary code so that a user can perform the following query operations (the argument’s values are arbitrary, your code should be able to respond for any valid value consistently):

The typedef should declare the following behavior and the resolvers should behave consistently for the arguments’ logic:

  • All arguments for all queries are optional
  • All arguments MUST be passed along as Input Objects
  • All Input Object values MUST be either Scalar or Enum values
  • All filtering rules must follow what specified on Day 02 exercise

Technologies

Select the exercise on your preferred technology:

Learning resources

GraphQL Spec (June 2018)

Input Objects

Enums

GraphQL Org

A walk in GraphQL Series at Medium

Github Pages

A Walk in GraphQL

Collaborators

  • Ezequiel Alvarez — @ealvarezk
    Reviewer
  • Ezequiel Tejerina — @quequitejerina
    Python exercises contributor and reviewer
  • Franco Gribaudo — @fgriba
    Java exercises contributor and reviewer
  • Cristian Buffa — @cristianbuffa & José Ignacio Aguilera — @jiaguilera
    NetCore exercises contributors and reviewers
  • Javier Valderrama — @Jaxolotl
    Author, JavaScript exercise contributor and reviewer

--

--

Javier Valderrama

Engineering manager, Lead Software engineer, passionate educator and community evangelist.