Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declarative vs Programmatically GraphQL

I´m adopting GraphQL for new fullstack projects and I´ve already studies many of the concepts and started my first projects.

My question is related to use declarative vs programatically GraphQL schema definition. Basically all I can see in the GraphQL official site uses the declarative approach: you define the schema in one or more files like (thanks to this example here):

type Brand {
  name: String
  logoUrl: String
}
enum Gender {
  MALE
  FEMALE
}
type Image {
  thumbnailUrl: String
  smallUrl: String
  mediumUrl: String
  largeUrl: String
}
type Article {
  id: ID! # non-nullable, is guaranteed to exist on every article
  name: String
  thumbnailUrl: String
  brand: Brand
  genders: [Gender]
  images: [Image]
  recommendations: [Article]
}
type Query {
  Article(id: ID!): Article
  Articles: [Articles]
}

Very clean and concise code even for a somehow complex data structure.

But most of examples I see on web and even on books that I´ve studied use the programatically approach to build the schema, something like:

import { GraphQLObjectType, GraphQLInputObjectType } from 'graphql';
import {GraphQLNonNull, GraphQLID, GraphQLList } from 'graphql';
import { GraphQLString, GraphQLInt, GraphQLBoolean } from 'graphql';

import { UserType } from '../User/types';
import UserModel from '../../../models/User';

const fields = {
    _id: {
        type: new GraphQLNonNull(GraphQLID)
    },
    name: {
        type: GraphQLString
    },
    phone: {
        type: GraphQLString
    }
 };

const CompanyType = new GraphQLObjectType({
    name: 'Company',
    description: 'Company',
    fields: fields
 })


const Company = {
    type: CompanyType,
    description: 'Get single company',
    args: {
        id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLID)
        }
    },
    resolve(root, params) {

        params.deleted = false;

        return CompanyModel.find(params).exec();
    }
}

const Companies = {
    type: new GraphQLList(CompanyType),
    description: 'Get all companies',
    resolve(root) {
        const companies = CompanyModel.find({ deleted: false }).exec();
        if (!companies) {
            throw new Error('Error getting companies.')
        }
        return companies;   
    }
}

export default {
    Company,
    Companies
}

My goal is to build a large SaaS application, so the schema will get pretty complex and my worry is that the code gets complex pretty soon.

So, should I go for a declarative approach, a programmatically approach or a mix of two?

What is the best practices here?

like image 936
Mendes Avatar asked Jul 29 '17 14:07

Mendes


1 Answers

There's a good bit of discussion on this topic here and here.

IMHO, the biggest advantage to defining your schema in GraphQL schema language is the readability. It makes your schema easy to read and understand, especially to internal users who may be querying the endpoint but not actually involved in it's design. I think it also makes defining and changing the schema less error-prone.

On the other hand, defining the schema programatically offers a lot more flexibility. For example, if you use buildSchema, you're limited to passing in resolvers for just your queries and mutations. This works fine if you're ok with every type just utilizing the default resolver -- but what happens when you need to define resolvers for individual fields?

Defining the schema programatically allows you to define resolvers for individual fields within any of the types you specify. Not only does this help transform the data you're getting back from your database (turning that thumbanail_url into a thumbnailUrl field), but if those fields require additional database queries, it prevents them from firing off unless the field is actually requested, which can be a significant performance boost. As the documentation points out, this approach is also useful if you want to generate the schema automatically.

Personally, this is why I love graphql-tools makeExecutableSchema. It's kind of a middle-of-the-road approach, allowing you to define your types in a very clean way (using GraphQL schema language), while allowing for a good bit of flexibility in implementing resolvers.

like image 66
Daniel Rearden Avatar answered Sep 30 '22 07:09

Daniel Rearden