Published on
1 min read

DRY GraphQL definitions using interfaces

Authors

Interfaces are abstract types that contain a collection of fields that other types can implement. This is a great way to keep your GraphQL definitions DRY.

Defining an Interface

For example, Active Record timestamps are common across models. Instead of re-declaring them, define an interface:

# app/graphql/interfaces/active_record_timestamp.rb
ActiveRecordTimestamp = GraphQL::InterfaceType.define do
  name 'ActiveRecordTimestamp'
  field :createdAt, types.String, property: :created_at
  field :updatedAt, types.String, property: :updated_at
end

Ensure the interfaces folder is autoloaded in config/application.rb:

config.autoload_paths << Rails.root.join('app/graphql/interfaces')

Implementing the Interface

Now, use the interfaces keyword in your object types:

# app/graphql/types/article_type.rb
ArticleType = GraphQL::ObjectType.define do
  name "Article"
  interfaces [ActiveRecordTimestamp]

  field :id, types.Int
  field :title, types.String
  # ...
end

Reusing Return Types in Mutations

You can also use return_interfaces to standardize mutation results:

# app/graphql/interfaces/mutation_result.rb
MutationResult = GraphQL::InterfaceType.define do
  name "MutationResult"
  field :success, !types.Boolean
  field :notice, types.String
  field :errors, types[ValidationError]
end

Apply it to your relay mutation:

# app/graphql/mutations/create_article.rb
CreateArticle = GraphQL::Relay::Mutation.define do
  return_interfaces [MutationResult]
  # ...
  resolve ->(obj, input, ctx) {
    article = Article.create(...)
    {
      success: article.persisted?,
      notice: "Article created successfully",
      errors: article.errors
    }
  }
end
TwitterLinkedInHacker News