DEV Community

Rohit Ravikoti for Novvum

Posted on

GraphQL Code-First and SDL-First, the Current Landscape in Mid-2019

There has been a lot of buzz in the GraphQL community around code-first or SDL-first schema development as of late. The purpose of this blog is to shed some light on the current state of the ecosystem and help teams make a decision on which approach would be best for them.

To understand where we are today, it helps to take a look at how we got here.

Code-first: the original way to build a graphql schema

Facebook originally released graphql-js as a reference implementation for the GraphQL specification. The schema is defined as a plain javascript object:

const { GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql')

const schema = new GraphQLSchema({  
  query: new GraphQLObjectType({  
    name: 'Query',  
    fields: {  
      hello: {  
        type: GraphQLString,  
        args: {  
          name: { type: GraphQLString },  
        },  
        resolve: (_, args) => `Hello ${args.name || 'World!'}`,  
      },  
    },  
  }),  
})  
Enter fullscreen mode Exit fullscreen mode

Many people in the community felt that writing a schema in this way was very verbose, and it was challenging to have a mental model of the schema while implementing it.

Enter SDL

The Apollo team released graphql-tools, which popularized the Schema Definition Language (SDL). Here is what the same schema from above looks like defined in SDL:

type Query {  
  hello(name: String): String  
}  
Enter fullscreen mode Exit fullscreen mode

It was much easier to understand the structure of the schema with SDL and, ultimately made the schema design process much more intuitive. The Apollo team also came up with schema directives to accompany the SDL.

One significant tradeoff for the SDL-first approach is that resolvers need to be implemented separately from the schema definition. Consequently, various new challenges came about. Directives are also not a part of the core GraphQL specification.

The pendulum swings back to code-first

Tools like TypeGraphQL and GraphQL Nexus were released to reduce the verbosity of graphql-js and provide a much simpler way to develop schemas than the SDL approach. These tools are built with graphql-js at their core, so they do not have support for schema directives — here are issues requesting support for them in TypeGraphQL and GraphQL Nexus.

Federated schemas…

The Apollo team recently introduced the Schema Federation specification for building distributed graphs. It significantly improved on a lot of the pitfalls of schema stitching and enabled a truly distributed architecture. The specification utilizes schema directives, so individual schemas can provide hints to the gateway server on how they are related to one another.

apollofederation

The major problem here is that the code-first libraries are unable to support schema federation because they do not support directives. There have been issues submitted for TypeGraphQL and GraphQL Nexus requesting support, but there hasn’t been much progress as of yet.

So, code-first or SDL-first?

Innovation will come with its fair share of disruption, and the GraphQL ecosystem is no exception. There are risks and tradeoffs when selecting any toolset, and teams must carefully look at their circumstances to understand which approach suits their needs.

Here are a couple of suggestions:

  • If your team needs schema federation or directives, then it is best to go with the SDL-first approach until the ecosystem catches up.
  • If your team doesn’t need schema federation or directives, then it is best to go with code-first — especially if you have a large schema. It will help your team keep your codebases organized and moving quickly.

What if you made the wrong choice?

The silver lining here is that you are not necessarily stuck with the decision your team makes now. Because both approaches are fundamentally the same (you define a schema and resolvers), it is not difficult to reuse most if not all of the business logic when switching from one approach to the other. One thing to note is that it is currently much easier to start with code-first and then switch to SDL-first because of the lack of schema directive support in code-first.

I hope this proved helpful for teams struggling to stay on top of everything that is happening in the GraphQL ecosystem. You can always reach out to us at Novvum for help!

about us: Novvum is a modern software development agency specializing in engineering, strategy, & design.

Top comments (1)

Collapse
 
nodkz profile image
Pablo Damnhorns

You may try graphql-compose to unlock directives for TypeGraphQL and GraphQL Nexus.

import { SchemaComposer } from 'graphql-compose';

const schemaRaw = builSchemaWithNexusOrTypeGraphQL();

const sc = new SchemaComposer(schemaRaw);
sc.getOTC('User').setDirectives([{ name: 'key', args: { fields: 'id'}}]);
// modify types as you wish 
// https://graphql-compose.github.io/docs/api/ObjectTypeComposer.html#directive-methods

// export only what you need for federation
// https://github.com/graphql-compose/graphql-compose/releases/tag/v7.11.0
const typeDefs = sc.getSDL({ include: ['User', 'AndJustSomeAnotherEntity'] });
const resolvers = sc.getResolveMethods();

resolvers.User.__resolveReference = (user) => {
   return fetchUserById(user.id)
};
resolvers.AndJustSomeAnotherEntity.__resolveReference = (entity) => {
   return fetchEntityById(entity.id)
};

const server = new ApolloServer({
  schema: buildFederatedSchema([{ typeDefs, resolvers }])
});

So with such approach you may pick only what you want and expose via apollo federation.