Repository is archived
No release in over 3 years
Low commit activity in last 3 years
Schema directives for graphql-ruby
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 2.0
~> 5.12
~> 12.0
~> 1.1

Runtime

~> 1.9
 Project Readme

This repository is no longer relevant

Ruby GraphQL Schema Directives

This gem extends GraphQL Ruby to add support for custom schema directives that annotate an SDL for uses such as Schema Stitching. This is a more generic version of the apollo-federation gem (which is specifically tailored to setting up the federation spec).

This gem has some very basic goals:

  1. allow schema directives to be applied to any GraphQL element, and then printed as an annotated SDL.
  2. allow class-based schemas and parsed GraphQL::Schema.from_definition schemas to be printed together.

Contents

  • Installation
  • Class-based schemas
  • Schema from type definitions

Installation

Add to Gemfile:

gem 'graphql-schema_directives'

Then install:

bundle install

Class-based schemas

There's a typed mixin available for extending all GraphQL schema members. The first thing to include is the schema mixin:

class MySchema < GraphQL::Schema
  include GraphQL::SchemaDirectives::Schema
end

This adds a print_schema_with_directives method to print an SDL that includes custom schema directives:

MySchema.print_schema_with_directives

Field, Object & Interface classes

Setup base abstracts:

class BaseField < GraphQL::Schema::Field
  include GraphQL::SchemaDirectives::Field
end

class BaseObject < GraphQL::Schema::Object
  include GraphQL::SchemaDirectives::Object
  field_class BaseField
end

module BaseInterface
  include GraphQL::Schema::Interface
  include GraphQL::SchemaDirectives::Interface
  field_class BaseField
end

Then extend into concrete implementations:

module Spaceship
  include BaseInterface
  add_directive :attribute, { speed: 'average' }

  field :name, String, null: false, directives: {
    cost: { value: 'FIELD' },
    public: nil
  }
end

class XWing < BaseObject
  implements Spaceship
  add_directive :attribute, { speed: 'fast' }
  add_directive :rebel

  field :name, String, null: false, directives: {
    cost: { value: 'FIELD' },
    public: nil
  }
end

Prints as:

interface Spaceship @attribute(speed: "average") {
  name: String! @cost(value: "FIELD") @public
}

type XWing @attribute(speed: "fast") @rebel {
  name: String! @cost(value: "FIELD") @public
}

Argument & InputObject classes

Base abstracts:

class BaseArgument < GraphQL::Schema::Argument
  include GraphQL::SchemaDirectives::Argument
end

class BaseInputObject < GraphQL::Schema::InputObject
  include GraphQL::SchemaDirectives::InputObject
  argument_class BaseArgument
end

Concrete implementation:

class FormInput < BaseInputObject
  add_directive :oneField
  argument :choice, String, required: true, directives: {
    cost: { value: 'INPUT' },
    public: nil
  }
end

Prints as:

input FormInput @oneField {
  choice: String! @cost(value: "INPUT") @public
}

EnumValue & Enum classes

Base abstracts:

class BaseEnumValue < GraphQL::Schema::EnumValue
  include GraphQL::SchemaDirectives::EnumValue
end

class BaseEnum < GraphQL::Schema::Enum
  include GraphQL::SchemaDirectives::Enum
  enum_value_class BaseEnumValue
end

Concrete implementation:

class FormOption < BaseEnum
  add_directive :dunno
  value 'GET', directives: { cost: { value: 'READ' }, public: nil }
  value 'SET', directives: { cost: { value: 'WRITE' }, public: nil }
end

Prints as:

enum FormOption @dunno {
  GET @cost(value: "READ") @public
  SET @cost(value: "WRITE") @public
}

Other classes

Base abstracts:

class BaseUnion < GraphQL::Schema::Union
  include GraphQL::SchemaDirectives::Union
end

class BaseScalar < GraphQL::Schema::Scalar
  include GraphQL::SchemaDirectives::Scalar
end

Schema from type definitions

You may also parse and print SDLs using the gem's from_definition method:

schema = GraphQL::SchemaDirectives.from_definition(type_defs)
puts schema.print_schema_with_directives

The local from_definition method accepts all the same options as the underlying method. Calling print_schema_with_directives works exactly like the default printer when operating on an unmodified document parse (elements with an original AST will print their schema directives natively).

This feature becomes useful when you start modifying a parsed document with class-based additions:

module Spaceship
  include GraphQL::Schema::Interface
  include GraphQL::SchemaDirectives::Interface
  field :name, String, null: false, directives: { public: nil }
end

type_defs = %(
  type XWing {
    name: String! @public
  }
  type Query {
    ship: XWing
  }
  schema {
    query: Query
  }
)

schema = GraphQL::SchemaDirectives.from_definition(type_defs)
schema.types['XWing'].implements(Spaceship)
puts schema.print_schema_with_directives

Using print_schema_with_directives will include directives from the original AST as well as directives applied to added classes.