File: introduction.md

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (255 lines) | stat: -rw-r--r-- 9,755 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
---
layout: guide
doc_stub: false
search: true
section: Fields
title: Introduction
desc: Implement fields and resolvers with the Ruby DSL
index: 0
---


Object fields expose data about that object or connect the object to other objects. You can add fields to your object types with the `field(...)` class method, for example:

```ruby
field :name, String, "The unique name of this list", null: false
```

{% internal_link "Objects", "/type_definitions/objects" %} and {% internal_link "Interfaces", "/type_definitions/interfaces" %} have fields.

The different elements of field definition are addressed below:

- [Names](#field-names) identify the field in GraphQL
- [Return types](#field-return-type) say what kind of data this field returns
- [Documentation](#field-documentation) includes description and deprecation notes
- [Resolution behavior](#field-resolution) hooks up Ruby code to the GraphQL field
- [Arguments](#field-arguments) allow fields to take input when they're queried
- [Extra field metadata](#extra-field-metadata) for low-level access to the GraphQL-Ruby runtime
- [Add default values for field parameters](#field-parameter-default-values)

## Field Names

A field's name is provided as the first argument or as the `name:` option:

```ruby
field :team_captain, ...
# or:
field ..., name: :team_captain
```

Under the hood, GraphQL-Ruby **camelizes** field names, so `field :team_captain, ...` would be `{ teamCaptain }` in GraphQL. You can disable this behavior by adding `camelize: false` to your field definition or to the [default field options](#field-parameter-default-values).

The field's name is also used as the basis of [field resolution](#field-resolution).

## Field Return Type

The second argument to `field(...)` is the return type. This can be:

- A built-in GraphQL type (`Integer`, `Float`, `String`, `ID`, or `Boolean`)
- A GraphQL type from your application
- An _array_ of any of the above, which denotes a {% internal_link "list type", "/type_definitions/lists" %}.

{% internal_link "Nullability", "/type_definitions/non_nulls" %} is expressed with the `null:` keyword:

- `null: true` (default) means that the field _may_ return `nil`
- `null: false` means the field is non-nullable; it may not return `nil`. If the implementation returns `nil`, GraphQL-Ruby will return an error to the client.

Additionally, list types maybe nullable by adding `[..., null: true]` to the definition.

Here are some examples:

```ruby
field :name, String # `String`, may return a `String` or `nil`
field :id, ID, null: false # `ID!`, always returns an `ID`, never `nil`
field :teammates, [Types::User], null: false # `[User!]!`, always returns a list containing `User`s
field :scores, [Integer, null: true] # `[Int]`, may return a list or `nil`, the list may contain a mix of `Integer`s and `nil`s
```

## Field Documentation

Fields may be documented with a __description__ and may be __deprecated__.

__Descriptions__ can be added with the `field(...)` method as a positional argument, a keyword argument, or inside the block:

```ruby
# 3rd positional argument
field :name, String, "The name of this thing", null: false

# `description:` keyword
field :name, String, null: false,
  description: "The name of this thing"

# inside the block
field :name, String, null: false do
  description "The name of this thing"
end
```

__Deprecated__ fields can be marked by adding a `deprecation_reason:` keyword argument:

```ruby
field :email, String,
  deprecation_reason: "Users may have multiple emails, use `User.emails` instead."
```

Fields with a `deprecation_reason:` will appear as "deprecated" in GraphiQL.

## Field Resolution

In general, fields return Ruby values corresponding to their GraphQL return types. For example, a field with the return type `String` should return a Ruby string, and a field with the return type `[User!]!` should return a Ruby array with zero or more `User` objects in it.

By default, fields return values by:

- Trying to call a method on the underlying object; _OR_
- If the underlying object is a `Hash`, lookup a key in that hash.
- An optional `:fallback_value` can be supplied that will be used if the above fail.

The method name or hash key corresponds to the field name, so in this example:

```ruby
field :top_score, Integer, null: false
```

The default behavior is to look for a `#top_score` method, or lookup a `Hash` key, `:top_score` (symbol) or `"top_score"` (string).

You can override the method name with the `method:` keyword, or override the hash key(s) with the `hash_key:` or `dig:` keyword, for example:

```ruby
# Use the `#best_score` method to resolve this field
field :top_score, Integer, null: false,
  method: :best_score

# Lookup `hash["allPlayers"]` to resolve this field
field :players, [User], null: false,
  hash_key: "allPlayers"

# Use the `#dig` method on the hash with `:nested` and `:movies` keys
field :movies, [Movie], null: false,
  dig: [:nested, :movies]
```

To pass-through the underlying object without calling a method on it, you can use `method: :itself`:

```ruby
field :player, User, null: false,
  method: :itself
```

This is equivalent to:

```ruby
field :player, User, null: false

def player
  object
end
```

If you don't want to delegate to the underlying object, you can define a method for each field:

```ruby
# Use the custom method below to resolve this field
field :total_games_played, Integer, null: false

def total_games_played
  object.games.count
end
```

Inside the method, you can access some helper methods:

- `object` is the underlying application object (formerly `obj` to resolve functions)
- `context` is the query context (passed as `context:` when executing queries, formerly `ctx` to resolve functions)

Additionally, when you define arguments (see below), they're passed to the method definition, for example:

```ruby
# Call the custom method with incoming arguments
field :current_winning_streak, Integer, null: false do
  argument :include_ties, Boolean, required: false, default_value: false
end

def current_winning_streak(include_ties:)
  # Business logic goes here
end
```

As the examples above show, by default the custom method name must match the field name. If you want to use a different custom method, the `resolver_method` option is available:

```ruby
# Use the custom method with a non-default name below to resolve this field
field :total_games_played, Integer, null: false, resolver_method: :games_played

def games_played
  object.games.count
end
```

`resolver_method` has two main use cases:

1. resolver re-use between multiple fields
2. dealing with method conflicts (specifically if you have fields named `context` or `object`)

Note that `resolver_method` _cannot_ be used in combination with `method` or `hash_key`.

## Field Arguments

_Arguments_ allow fields to take input to their resolution. For example:

- A `search()` field may take a `term:` argument, which is the query to use for searching, eg `search(term: "GraphQL")`
- A `user()` field may take an `id:` argument, which specifies which user to find, eg `user(id: 1)`
- An `attachments()` field may take a `type:` argument, which filters the result by file type, eg `attachments(type: PHOTO)`

Read more in the {% internal_link "Arguments guide", "/fields/arguments" %}

## Extra Field Metadata

Inside a field method, you can access some low-level objects from the GraphQL-Ruby runtime. Be warned, these APIs are subject to change, so check the changelog when updating.

A few `extras` are available:

- `ast_node`
- `graphql_name` (the field's name)
- `owner` (the type that this field belongs to)
- `lookahead` (see {% internal_link "Lookahead", "/queries/lookahead" %})
- `execution_errors`, whose `#add(err_or_msg)` method should be used for adding errors
- `argument_details` (Intepreter only), an instance of {{ "GraphQL::Execution::Interpreter::Arguments" | api_doc }} with argument metadata
- `parent` (the previous `object` in the query)
- Custom extras, see below

To inject them into your field method, first, add the `extras:` option to the field definition:

```ruby
field :my_field, String, null: false, extras: [:ast_node]
```

Then add `ast_node:` keyword to the method signature:

```ruby
def my_field(ast_node:)
  # ...
end
```

At runtime, the requested runtime object will be passed to the field.

__Custom extras__ are also possible. Any method on your field class can be passed to `extras: [...]`, and the value will be injected into the method. For example, `extras: [:owner]` will inject the object type who owns the field. Any new methods on your custom field class may be used, too.

## Field Parameter Default Values

The field method requires you to pass `null:` keyword argument to determine whether the field is nullable or not. For another field you may want to override `camelize`, which is `true` by default. You can override this behavior by adding a custom field with overwritten `camelize` option, which is `true` by default.

```ruby
class CustomField < GraphQL::Schema::Field
  # Add `null: false` and `camelize: false` which provide default values
  # in case the caller doesn't pass anything for those arguments.
  # **kwargs is a catch-all that will get everything else
  def initialize(*args, null: false, camelize: false, **kwargs, &block)
    # Then, call super _without_ any args, where Ruby will take
    # _all_ the args originally passed to this method and pass it to the super method.
    super
  end
end
```

To use `CustomField` in your Objects and Interfaces, you'll need to register it as a `field_class` on those classes. See  [Customizing Fields](https://graphql-ruby.org/type_definitions/extensions#customizing-fields) for more information on how to do so.