A walk in GraphQL — Extending SDL definitions — Day 6

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

Javier Valderrama
7 min readMay 24, 2021

Extend

The extend keyword in SDL provides the ability to add properties to existing SDL definitions.

What kind of definitions can you extend and what can you add to them?

Syntax summary from the GraphQL spec

GraphQL spec — June 2018 — B.3 Document

SchemaExtension
extend schema Directives { OperationTypeDefinitions }
extend schema Directives

ScalarTypeExtension
extend scalar Name Directives

ObjectTypeExtension
extend type Name ImplementsInterfaces Directives FieldsDefinitions
extend type Name ImplementsInterfaces Directives
extend type Name ImplementsInterfaces

InterfaceTypeExtension
extend interface Name Directives FieldsDefinitions
extend interface Name Directives

UnionTypeExtension
extend union Name Directives UnionMemberTypes
extend union Name Directives

EnumTypeExtension
extend enum Name Directives EnumValuesDefinitions
extend enum Name Directives

InputObjectTypeExtension
extend input Name Directives InputFieldsDefinition
extend input Name Directives

Does it mean we can extend pretty much everything declared in an existing schema?

Yup

With great power comes great responsibility 🕸

Clearly this has specific rules:

  • What you are extending must be already declared.
  • Anything you add must not already apply to the original definition.

And comes at a great cost:

  • As opposite to what extend concept implies for other languages, in SLD there’s no place for inheritance, subclassing, etc., you’re actually extending the original thing … by modifying it. E.g. you cannot do something like type MyType extends MyOtherType, you just extend type MyType and now the original MyType has been modified with the new thing you added to it.
  • Again, extend is a modifier.

What’s the use?

Now that we know the syntax, the rules and the cost … gimme the benefits dude!!!!

You may say: — hey! I could use extend instead of dealing with interface complexity
— well, sort of, if you don’t want the implementation contract of the interface, but maybe you didn’t want an interface at all from the beginning.

— hey! I may extend the Operation Type Definitions in order to organize it more clearly on my file adding the queries, mutations and subscriptions close to the related Object Types they’re dealing with!
— Now we’re on the good track!!!

Let’s go back to our previous example:

A pretty simple file with a simple domain complexity, still, if we start organizing it differently it’s gonna be easier to understand.

An underlying pattern is becoming evident, we have at least two potential domains, right?, now imagine if Sword, Realm, City types are added … and this is still a ridiculously small app!!! and as a seasoned engineer you might want to separate them into specific files, maybe in specific directories and so on; well, here’s where things become complicated.

Scaling your Schema

There’s so much to say about this argument, and the considerations will vary depending on the prerequisites and circumstances, e.g. the project type (personal, enterprise, experimental), the scale (single person, small team, multiple teams, distributed teams) and many other! So in a high level overview we’ll mention some of those considerations and leave you the links to the most valuable documents I’ve seen so far which represent the best practices determined by the industry after years of designing GraphQL at scale. One of the most relevant documents is the “Principled GraphQL”, written by Geoff Schmidt and Matt DeBergalis, which we’ll mention several times in this chapter, but it’s not the only one as many great engineers are sharing with all of us their invaluable experience.

Graph Breakdown

One of the first things that will hit you is the “One Graph” principle which by any means is referred to have one single file; it means that you have to have a single source of truth (one unified graph) that represents the interactions between the actors and the data through Aggregates (Objects & Relationships), Views (Queries) and Commands (Mutations); here is where we have 2 primary options, the Monolithic architecture (e.g. Schema Stitching), and the Federated architecture, (e.g. Apollo Federation). Other options like graphql-modules combine the declaration and execution code all together but we won’t describe it here. While the former is considered deprecated or not recommended for many reasons we’ll see later, we still encourage you to know it and practice it because:

  1. It’s still applies to small project
  2. You’ll still find it alive and kicking in many projects
  3. The migration from schema stitching to federation is thoroughly documented, and you may consider this process the natural evolution of small or legacy projects when the need for scale arise.

Clearly this discussion is around architecture and not about GraphQL explicitly, therefore the actual implementation will depend on the technology. We’ll see the concept as detached from the technologies as possible but when a particular example will require it, we’ll use Apollo’s related technologies as it’s leading the trend for now.

Here some of the most evident differences between Schema Stitching and Apollo Federation

Another summarized high level description we like can be read in GraphQL Federation vs Stitching by Gunar Gessner.

All above is only achievable thanks to extend, a simple keyword on the spec is the door that opens towards hell or heaven depending on how you use it.

Schema Stitching example

In order to keep the learning path more natural and start with the simplest example we will go for the Stitching technique for now and dedicate a whole day for Federation in the future.

SDL

So how our example would look like if we use the stitching technique?

schema.gql

character.gql

magicalCreature.gql

Resolvers

And the resolvers?

Well, you might separate them into specific files too or keep them in one place, again, that’s an engineering concern and will depend on the technology, GraphQL just doesn’t care, granted they’re passed along with the type definitions to the server.

Server

See here how our implementation might look like using Apollo Server in an oversimplified example.

When things go wrong (︶︹︶)

a.k.a. how to resolve conflicts

So far our example worked smoothly just because we were moving a working SDL document to 3 documents, but what happens when the number of documents and lines of code scale and you need to handle fields, types or other conflicts? Clearly just importing the SDL files won’t work anymore. In this case you’ll have to leverage the existing tools available for your technology or eventually write your own if nothing fit your needs.

graphql-tools/merge

You might still find some previous implementations using graphql-tools/mergeSchemas which has been deprecated in favor of the above mentioned.

See below the migration tutorial and some old documentation as you might still find it in a project.

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

This exercise might require additional instructions depending on the technology, please read them carefully before starting.

Schema

  • Identify and separate the SDL document into 4 documents in a per-type basis
  • Here a completely arbitrary example (you can experiment different setups if you want)
    — globalSearch.gql
    — person.gql
    — schema.gql
    — skill.gql
  • Update the server app in order to include and stitch all schemas together
  • You can directly import the *.gql files or use a technology specific utility like apollo-tools or whatever you want

As you can see, the challenge here will depend on the technology and we encourage you to experiment and try different approaches.

Operations list

All previous operations MUST work regardless the stitching technique implemented.

Technologies

Select the exercise on your preferred technology:

Learning resources

GraphQL Spec (June 2018)

Apollo Blog

Apollo GraphQL

graphql-tools

Advanced GraphQL dot com

Youtube

Other articles

GraphCMS

Ariadne

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

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Javier Valderrama
Javier Valderrama

Written by Javier Valderrama

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

No responses yet

Write a response