directives.go

  1package graphql
  2
  3const (
  4	// Operations
  5	DirectiveLocationQuery              = "QUERY"
  6	DirectiveLocationMutation           = "MUTATION"
  7	DirectiveLocationSubscription       = "SUBSCRIPTION"
  8	DirectiveLocationField              = "FIELD"
  9	DirectiveLocationFragmentDefinition = "FRAGMENT_DEFINITION"
 10	DirectiveLocationFragmentSpread     = "FRAGMENT_SPREAD"
 11	DirectiveLocationInlineFragment     = "INLINE_FRAGMENT"
 12
 13	// Schema Definitions
 14	DirectiveLocationSchema               = "SCHEMA"
 15	DirectiveLocationScalar               = "SCALAR"
 16	DirectiveLocationObject               = "OBJECT"
 17	DirectiveLocationFieldDefinition      = "FIELD_DEFINITION"
 18	DirectiveLocationArgumentDefinition   = "ARGUMENT_DEFINITION"
 19	DirectiveLocationInterface            = "INTERFACE"
 20	DirectiveLocationUnion                = "UNION"
 21	DirectiveLocationEnum                 = "ENUM"
 22	DirectiveLocationEnumValue            = "ENUM_VALUE"
 23	DirectiveLocationInputObject          = "INPUT_OBJECT"
 24	DirectiveLocationInputFieldDefinition = "INPUT_FIELD_DEFINITION"
 25)
 26
 27// DefaultDeprecationReason Constant string used for default reason for a deprecation.
 28const DefaultDeprecationReason = "No longer supported"
 29
 30// SpecifiedRules The full list of specified directives.
 31var SpecifiedDirectives = []*Directive{
 32	IncludeDirective,
 33	SkipDirective,
 34	DeprecatedDirective,
 35}
 36
 37// Directive structs are used by the GraphQL runtime as a way of modifying execution
 38// behavior. Type system creators will usually not create these directly.
 39type Directive struct {
 40	Name        string      `json:"name"`
 41	Description string      `json:"description"`
 42	Locations   []string    `json:"locations"`
 43	Args        []*Argument `json:"args"`
 44
 45	err error
 46}
 47
 48// DirectiveConfig options for creating a new GraphQLDirective
 49type DirectiveConfig struct {
 50	Name        string              `json:"name"`
 51	Description string              `json:"description"`
 52	Locations   []string            `json:"locations"`
 53	Args        FieldConfigArgument `json:"args"`
 54}
 55
 56func NewDirective(config DirectiveConfig) *Directive {
 57	dir := &Directive{}
 58
 59	// Ensure directive is named
 60	err := invariant(config.Name != "", "Directive must be named.")
 61	if err != nil {
 62		dir.err = err
 63		return dir
 64	}
 65
 66	// Ensure directive name is valid
 67	err = assertValidName(config.Name)
 68	if err != nil {
 69		dir.err = err
 70		return dir
 71	}
 72
 73	// Ensure locations are provided for directive
 74	err = invariant(len(config.Locations) > 0, "Must provide locations for directive.")
 75	if err != nil {
 76		dir.err = err
 77		return dir
 78	}
 79
 80	args := []*Argument{}
 81
 82	for argName, argConfig := range config.Args {
 83		err := assertValidName(argName)
 84		if err != nil {
 85			dir.err = err
 86			return dir
 87		}
 88		args = append(args, &Argument{
 89			PrivateName:        argName,
 90			PrivateDescription: argConfig.Description,
 91			Type:               argConfig.Type,
 92			DefaultValue:       argConfig.DefaultValue,
 93		})
 94	}
 95
 96	dir.Name = config.Name
 97	dir.Description = config.Description
 98	dir.Locations = config.Locations
 99	dir.Args = args
100	return dir
101}
102
103// IncludeDirective is used to conditionally include fields or fragments.
104var IncludeDirective = NewDirective(DirectiveConfig{
105	Name: "include",
106	Description: "Directs the executor to include this field or fragment only when " +
107		"the `if` argument is true.",
108	Locations: []string{
109		DirectiveLocationField,
110		DirectiveLocationFragmentSpread,
111		DirectiveLocationInlineFragment,
112	},
113	Args: FieldConfigArgument{
114		"if": &ArgumentConfig{
115			Type:        NewNonNull(Boolean),
116			Description: "Included when true.",
117		},
118	},
119})
120
121// SkipDirective Used to conditionally skip (exclude) fields or fragments.
122var SkipDirective = NewDirective(DirectiveConfig{
123	Name: "skip",
124	Description: "Directs the executor to skip this field or fragment when the `if` " +
125		"argument is true.",
126	Args: FieldConfigArgument{
127		"if": &ArgumentConfig{
128			Type:        NewNonNull(Boolean),
129			Description: "Skipped when true.",
130		},
131	},
132	Locations: []string{
133		DirectiveLocationField,
134		DirectiveLocationFragmentSpread,
135		DirectiveLocationInlineFragment,
136	},
137})
138
139// DeprecatedDirective  Used to declare element of a GraphQL schema as deprecated.
140var DeprecatedDirective = NewDirective(DirectiveConfig{
141	Name:        "deprecated",
142	Description: "Marks an element of a GraphQL schema as no longer supported.",
143	Args: FieldConfigArgument{
144		"reason": &ArgumentConfig{
145			Type: String,
146			Description: "Explains why this element was deprecated, usually also including a " +
147				"suggestion for how to access supported similar data. Formatted" +
148				"in [Markdown](https://daringfireball.net/projects/markdown/).",
149			DefaultValue: DefaultDeprecationReason,
150		},
151	},
152	Locations: []string{
153		DirectiveLocationFieldDefinition,
154		DirectiveLocationEnumValue,
155	},
156})