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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With