lighthouse-graphql 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +118 -1
- data/README.md +24 -16
- data/docs/caching.md +4 -3
- data/docs/configuration.md +1 -21
- data/docs/directives.md +14 -7
- data/docs/generators.md +41 -39
- data/docs/getting-started.md +88 -51
- data/docs/performance.md +2 -2
- data/docs/relationships.md +5 -4
- data/docs/relay.md +63 -0
- data/docs/resolvers.md +90 -37
- data/docs/security.md +64 -16
- data/docs/subscriptions.md +16 -9
- data/docs/types.md +16 -17
- data/docs/uploads.md +41 -14
- data/lib/generators/lighthouse/base_classes.rb +9 -14
- data/lib/generators/lighthouse/install/graphql_ruby_install.rb +113 -0
- data/lib/generators/lighthouse/install/install_generator.rb +112 -91
- data/lib/generators/lighthouse/install/templates/initializer.rb.tt +3 -9
- data/lib/lighthouse/caching.rb +9 -3
- data/lib/lighthouse/config.rb +6 -23
- data/lib/lighthouse/controller.rb +28 -5
- data/lib/lighthouse/directive_resolvers/argument_transforms_resolver.rb +18 -18
- data/lib/lighthouse/directive_resolvers/cache_resolvers.rb +1 -1
- data/lib/lighthouse/directive_resolvers/global_id_resolver.rb +3 -1
- data/lib/lighthouse/directive_resolvers/throttle_resolver.rb +85 -26
- data/lib/lighthouse/directive_resolvers/type_method_resolver.rb +12 -6
- data/lib/lighthouse/directives/arguments/more_filters.rb +1 -1
- data/lib/lighthouse/field_resolver_stack.rb +9 -6
- data/lib/lighthouse/global_id.rb +29 -3
- data/lib/lighthouse/graphql/version.rb +1 -1
- data/lib/lighthouse/graphql_ruby_patches.rb +45 -0
- data/lib/lighthouse/rb_lighthouse.rb +1 -0
- data/lib/lighthouse/resolver_bases.rb +18 -4
- data/lib/lighthouse/resolver_dispatch.rb +16 -1
- data/lib/lighthouse/root_types.rb +117 -0
- data/lib/lighthouse/schema_generator.rb +4 -3
- data/lib/lighthouse/upload.rb +4 -2
- data/lib/lighthouse/upload_store.rb +39 -14
- data/sig/lighthouse.rbs +0 -10
- metadata +3 -4
- data/lib/generators/lighthouse/install/templates/schema.rb.tt +0 -29
- data/lib/generators/lighthouse/mutation_generator.rb +0 -31
- data/lib/generators/lighthouse/query_generator.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da632a31f353bc75d798a228769150a76f8cd3a0e8dce13e8bc19c363641f850
|
|
4
|
+
data.tar.gz: 6d0e92dc7818bccd89d4d9d1bc2e4905421cedd84190a0d0ae09c8ad31cb546f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30c076b60a32754472f1360eedc72c46b2ee518230d8ce686658f6a436f9a7d74cbcb13c24bf6a1d7dc8c05f29fba8f6ddd0d53e5614ea00ab498753340429c3
|
|
7
|
+
data.tar.gz: d558ad506a5bfebda1486cf8b62450113d0a1022f0ff458a8b040924aca458189a176cf9dbdcab95f877b571bfc18b1408109b5db36bfc128a6754df55b1bc11
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,122 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.6.0] - 2026-10-18
|
|
10
|
+
|
|
11
|
+
Lighthouse now uses what the Rails app and graphql-ruby already have instead of settings and
|
|
12
|
+
files of its own: the app's cache, its controllers' rate limiting, its ActiveStorage, and
|
|
13
|
+
everything graphql-ruby's `graphql:install` writes, which `lighthouse:install` now builds on.
|
|
14
|
+
Several defaults change.
|
|
15
|
+
|
|
16
|
+
**Upgrading from 0.5:**
|
|
17
|
+
|
|
18
|
+
1. Remove `config.cache_store =` and `config.upload_store =` from
|
|
19
|
+
`config/initializers/lighthouse.rb`. Configure the app's `config.cache_store` instead, and
|
|
20
|
+
`config.action_controller.cache_store` if rate limits should be counted somewhere else.
|
|
21
|
+
2. `@throttle` counts per IP now. Add `by: "current_user.id"` where a field counted per user.
|
|
22
|
+
3. Past a `@throttle` limit the request is answered with a 429, as Rails' `rate_limit` answers it.
|
|
23
|
+
To fail only the field, as before, give `with:` a controller method that raises a
|
|
24
|
+
`GraphQL::ExecutionError`.
|
|
25
|
+
4. `@upload` checks `public:` against the ActiveStorage service. On a public service, add
|
|
26
|
+
`public: true`. Where `public: true` meets a private service, name a public one with `disk:`.
|
|
27
|
+
5. `rails g lighthouse:query` and `lighthouse:mutation` are gone. Resolve a root field with a
|
|
28
|
+
method of `Types::QueryType` / `MutationType`, with `rails g graphql:mutation`, or with a
|
|
29
|
+
`Resolvers::` / `Mutations::` class written by hand, which convention still finds. An app
|
|
30
|
+
installed with 0.5 keeps working as it is: `AppSchema = get_schema(...)` is still supported.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `@throttle(by:)`: who the client is, as `rate_limit`'s `by:`. It is a path in the context, read
|
|
35
|
+
as `@inject` reads one (`by: "current_user.id"`).
|
|
36
|
+
- `@throttle(with:)`: a controller method to call past the limit, as `rate_limit`'s `with:`. One
|
|
37
|
+
that renders or redirects ends the request with its response, as a `before_action` that renders
|
|
38
|
+
does. One that returns lets the call through, and one that raises a `GraphQL::ExecutionError`
|
|
39
|
+
fails only the field.
|
|
40
|
+
- `@throttle` refusals are instrumented as `rate_limit.action_controller`, with `rate_limit`'s
|
|
41
|
+
payload (`request`, `count`, `to`, `within`, `by`, `name`, `scope`, `cache_key`).
|
|
42
|
+
- `base_types` takes graphql-ruby's code-first root types and Node interface. The SDL's root type
|
|
43
|
+
of a kind is built on `query_type:` / `mutation_type:` / `subscription_type:` (`Types::QueryType`),
|
|
44
|
+
so the `field`s the class declares (graphql-ruby's Relay `node` and `nodes`, what
|
|
45
|
+
`graphql:mutation` adds to `Types::MutationType`) are the schema's too, beside the SDL's, and
|
|
46
|
+
resolve as in graphql-ruby. With no such root type in the SDL, the class is the root. `node:`
|
|
47
|
+
(`Types::NodeType`) is the SDL's `Node` interface, which `@node` types implement, so
|
|
48
|
+
graphql-ruby's Relay and `@node` share one `Node`.
|
|
49
|
+
- A root field with no resolving directive resolves with the method of its name on the root type
|
|
50
|
+
class, when the class includes `Lighthouse::GraphQL::Type` (`Query.latestPosts` →
|
|
51
|
+
`Types::QueryType#latest_posts`), before the conventional `Resolvers::` / `Mutations::` class.
|
|
52
|
+
- A schema that implements graphql-ruby's `id_from_object` / `object_from_id` has one kind of
|
|
53
|
+
global id: `@globalId` encodes an object's own id with `id_from_object`, and decodes an
|
|
54
|
+
argument with `object_from_id`.
|
|
55
|
+
- `lighthouse:install --subscriptions` writes `Subscriptions::BaseSubscription` and names it in
|
|
56
|
+
`base_types`; without it, the install writes no subscription base.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- `@cache`, `@clearCache` and Automatic Persisted Queries use the app's `Rails.cache`
|
|
61
|
+
(`config.cache_store`), as PHP Lighthouse uses Laravel's cache. Outside Rails they use an
|
|
62
|
+
in-memory store.
|
|
63
|
+
- `@throttle` is Rails' `rate_limit` on one field, and counts as it does:
|
|
64
|
+
- It counts in the controller's `cache_store` (`config.action_controller.cache_store`,
|
|
65
|
+
`Rails.cache` unless set), under `rate_limit`'s key, `rate-limit:<scope>:<name>:<by>`.
|
|
66
|
+
Counts kept under the old `lighthouse:throttle:` keys start over.
|
|
67
|
+
- `name:` is `rate_limit`'s. Each field counts under its own name (`Query.x`) by default, apart
|
|
68
|
+
from the controller's `rate_limit`, or together with it when both use the same name.
|
|
69
|
+
`prefix:` is `rate_limit`'s `scope:`, the controller's path by default.
|
|
70
|
+
- The client is its IP, as `rate_limit`'s default `by:`, no longer the signed-in user.
|
|
71
|
+
- Past the limit it does what `rate_limit` does by default: it raises
|
|
72
|
+
`ActionController::TooManyRequests`, which Rails answers with a 429
|
|
73
|
+
(`head :too_many_requests` on Rails 7.2). The field used to fail on its own, with the rest of
|
|
74
|
+
the operation answered; that remains the behavior without Action Pack.
|
|
75
|
+
- `lighthouse:install` builds on graphql-ruby's `graphql:install`, run with whichever of its
|
|
76
|
+
options the app chose (`--relay`, `--batch`, `--skip-mutation-root-type`, `--schema`,
|
|
77
|
+
`--directory`, `--api`), or run first with its defaults when the app has none. It writes no
|
|
78
|
+
schema class of its own: graphql-ruby's `class AppSchema < GraphQL::Schema` becomes
|
|
79
|
+
`class AppSchema < Lighthouse::GraphQL::RbLightHouse.get_schema(options: { base_types: ... })`,
|
|
80
|
+
naming every class graphql-ruby wrote, and keeps the rest of the class (`use
|
|
81
|
+
GraphQL::Dataloader`, `max_depth`, `id_from_object`, ...). It takes out what Lighthouse replaces:
|
|
82
|
+
the `query(...)` / `mutation(...)` root types the SDL's are built on, the `resolve_type` stub,
|
|
83
|
+
and the example `test_field`. Its base object, interface, union and scalar include
|
|
84
|
+
`Lighthouse::GraphQL::Type`, so every type class is Lighthouse's without an `include` of its
|
|
85
|
+
own. With `--batch`, the schema uses `GraphQL::Dataloader` too. Its `Mutations::BaseMutation`, a
|
|
86
|
+
`RelayClassicMutation`, is kept; graphql-ruby's controller, unchanged since its install, becomes
|
|
87
|
+
one with `Lighthouse::GraphQL::Controller`. `Types::QueryType` and `MutationType` are kept.
|
|
88
|
+
- An SDL Mutation field that declares its arguments one by one resolves by convention to a
|
|
89
|
+
`GraphQL::Schema::RelayClassicMutation` subclass as to a plain mutation, its arguments as
|
|
90
|
+
keywords. It used to fail looking for `input:`.
|
|
91
|
+
- A subscriptions backend the app's schema class `use`s in its body
|
|
92
|
+
(`use GraphQL::Subscriptions::ActionCableSubscriptions`) delivers the SDL's Subscription fields.
|
|
93
|
+
graphql-ruby adds its subscription extension only to a root type of the class's own.
|
|
94
|
+
- `Lighthouse::GraphQL::Controller` puts the controller in the context (`:lighthouse_controller`)
|
|
95
|
+
for `@throttle`. In development, an error Rails answers with a status of its own
|
|
96
|
+
(`config.action_dispatch.rescue_responses`, such as a 429 or a 404) now gets that status, as in
|
|
97
|
+
production, instead of being rendered as a JSON 500.
|
|
98
|
+
- `@upload` stores files on the app's ActiveStorage only, with PHP Lighthouse's rules. `disk:`
|
|
99
|
+
names a service of `config/storage.yml` (`config.active_storage.service` without it), and
|
|
100
|
+
`path:` starts the blob's key. ActiveStorage sets visibility per service, so `public:` must now
|
|
101
|
+
agree with the service's: `public: true` on a private service, or the default `false` on a
|
|
102
|
+
public one, fails instead of being ignored. An unknown service, or a value that is not a file,
|
|
103
|
+
fails naming the argument. The file is rewound before it is stored, so a `@validator` may read
|
|
104
|
+
it first.
|
|
105
|
+
- The `Upload` scalar's errors are PHP Lighthouse's: a value that is not a file names the GraphQL
|
|
106
|
+
multipart request specification and what was sent instead.
|
|
107
|
+
|
|
108
|
+
### Removed
|
|
109
|
+
|
|
110
|
+
- `Config.cache_store`: configure the app's `config.cache_store` instead, and
|
|
111
|
+
`config.action_controller.cache_store` (or a controller's `self.cache_store =`) for `@throttle`.
|
|
112
|
+
`Config.persisted_queries_store` stays, defaulting to `Rails.cache`.
|
|
113
|
+
- `Config.upload_store`: to store files elsewhere, declare an ActiveStorage service and name it
|
|
114
|
+
with `@upload(disk:)`, as a Laravel app declares a disk.
|
|
115
|
+
- `rails g lighthouse:query` and `lighthouse:mutation`: graphql-ruby has no resolver generator,
|
|
116
|
+
and `graphql:mutation` works in a Lighthouse app now. See Upgrading.
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- On graphql-ruby 2.5, a schema using `@limit`, `@bind` or `@upload` without one of their optional
|
|
121
|
+
arguments did not build (`Expected value to not be null`): graphql 2.5 does not apply the default
|
|
122
|
+
of a non-null directive argument. Those arguments (`builder`, `column`, `with`, `optional`,
|
|
123
|
+
`path`, `public`) are nullable now, with the same defaults.
|
|
124
|
+
|
|
9
125
|
## [0.5.0] - 2026-10-18
|
|
10
126
|
|
|
11
127
|
### Added
|
|
@@ -461,7 +577,8 @@ had been running inside a private monorepo as a path gem before being extracted.
|
|
|
461
577
|
- Config-driven extension seams: `Lighthouse.configure`, `resolver_namespaces`,
|
|
462
578
|
`on_error`, and `DirectiveRegistry.register` for app-defined directives.
|
|
463
579
|
|
|
464
|
-
[Unreleased]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.
|
|
580
|
+
[Unreleased]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.6.0...HEAD
|
|
581
|
+
[0.6.0]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.5.0...v0.6.0
|
|
465
582
|
[0.5.0]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.4.0...v0.5.0
|
|
466
583
|
[0.4.0]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.3.0...v0.4.0
|
|
467
584
|
[0.3.0]: https://github.com/Vaz-Innovation/lighthouse-graphql/compare/v0.2.1...v0.3.0
|
data/README.md
CHANGED
|
@@ -72,18 +72,22 @@ It depends on `graphql ~> 2.5` and `activesupport`. For federation you also need
|
|
|
72
72
|
On graphql 2.5, keep the `json` gem below 3: graphql 2.5 calls `JSON.generate`
|
|
73
73
|
with an option json 3 removed (graphql 2.6 no longer does).
|
|
74
74
|
|
|
75
|
-
Then let the
|
|
75
|
+
Then let the generators set the app up:
|
|
76
76
|
|
|
77
77
|
```shell
|
|
78
|
+
bin/rails generate graphql:install # graphql-ruby's, with the options you choose (optional)
|
|
78
79
|
bin/rails generate lighthouse:install
|
|
79
80
|
```
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
`lighthouse:install` builds on graphql-ruby's own install, and runs `graphql:install`
|
|
83
|
+
with its defaults when the app has none. It adapts what graphql-ruby wrote: the
|
|
84
|
+
schema class becomes Lighthouse's, built from the SDL on graphql-ruby's root types
|
|
85
|
+
and base classes, and the rest of its body stays; the base object, interface, union
|
|
86
|
+
and scalar include `Lighthouse::GraphQL::Type`; the controller serves the schema
|
|
87
|
+
through `Lighthouse::GraphQL::Controller`. It adds the initializer, a starter schema
|
|
88
|
+
in `graphql/schema.graphql` and a `graphql.config.yml` for your IDE. Run
|
|
85
89
|
`bin/rails generate lighthouse:install --help` for its options (`--schema`,
|
|
86
|
-
`--sdl-folder`, `--skip-controller`, `--skip-ide`), and see
|
|
90
|
+
`--sdl-folder`, `--subscriptions`, `--skip-controller`, `--skip-ide`), and see
|
|
87
91
|
[docs/generators.md](docs/generators.md) for every generator, graphql-ruby's included.
|
|
88
92
|
|
|
89
93
|
### IDE support
|
|
@@ -123,22 +127,26 @@ Prefer to wire it by hand? These are the steps the generator performs.
|
|
|
123
127
|
}
|
|
124
128
|
```
|
|
125
129
|
|
|
126
|
-
2. **Build the schema
|
|
130
|
+
2. **Build the schema**: graphql-ruby's schema class (`app/graphql/app_schema.rb`),
|
|
131
|
+
inheriting from the schema Lighthouse builds instead of `GraphQL::Schema`:
|
|
127
132
|
|
|
128
133
|
```ruby
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
AppSchema = Lighthouse::GraphQL::RbLightHouse.get_schema(
|
|
132
|
-
sdl_folder: Rails.root.join('graphql').to_s,
|
|
134
|
+
class AppSchema < Lighthouse::GraphQL::RbLightHouse.get_schema(
|
|
133
135
|
options: {
|
|
134
|
-
base_types: {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
base_types: { # the classes graphql-ruby's install writes
|
|
137
|
+
query_type: Types::QueryType,
|
|
138
|
+
mutation_type: Types::MutationType,
|
|
139
|
+
node: Types::NodeType,
|
|
140
|
+
resolver: Resolvers::BaseResolver,
|
|
141
|
+
mutation: Mutations::BaseMutation,
|
|
142
|
+
object: Types::BaseObject
|
|
143
|
+
# interface: Types::BaseInterface, union:, scalar:, enum:, input_object: ...
|
|
139
144
|
}
|
|
140
145
|
}
|
|
141
146
|
)
|
|
147
|
+
use GraphQL::Dataloader # Lighthouse batches relationships through it
|
|
148
|
+
max_depth(15)
|
|
149
|
+
end
|
|
142
150
|
```
|
|
143
151
|
|
|
144
152
|
3. **Execute** it from your controller exactly like any graphql-ruby schema:
|
data/docs/caching.md
CHANGED
|
@@ -41,9 +41,10 @@ such as a Relay connection object, is reported through
|
|
|
41
41
|
[`on_error`](configuration.md#on_error) and returned uncached. So cache list
|
|
42
42
|
fields, not connection fields.
|
|
43
43
|
|
|
44
|
-
The store is
|
|
45
|
-
|
|
46
|
-
you enable caching
|
|
44
|
+
The store is your app's cache, `Rails.cache` (`config.cache_store`), as PHP
|
|
45
|
+
Lighthouse uses Laravel's: Lighthouse keeps no store of its own. Note that Rails
|
|
46
|
+
uses a `:null_store` in development and test unless you enable caching
|
|
47
|
+
(`bin/rails dev:cache`).
|
|
47
48
|
|
|
48
49
|
A cached value is still authorized and validated on every request: `@cache` runs
|
|
49
50
|
inside `@guard`, `@can*` and `@validator`, never around them.
|
data/docs/configuration.md
CHANGED
|
@@ -70,15 +70,6 @@ reporter in production:
|
|
|
70
70
|
config.on_error = ->(error, _ctx) { Sentry.capture_exception(error) }
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
### `cache_store`
|
|
74
|
-
|
|
75
|
-
The store behind [`@cache` / `@clearCache`](caching.md). Defaults to
|
|
76
|
-
`Rails.cache` (an in-memory store outside Rails).
|
|
77
|
-
|
|
78
|
-
```ruby
|
|
79
|
-
config.cache_store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV['REDIS_URL'])
|
|
80
|
-
```
|
|
81
|
-
|
|
82
73
|
### `pagination_default_count`, `pagination_max_count`
|
|
83
74
|
|
|
84
75
|
Defaults for paginated fields: the `first` used when a client leaves it out (so
|
|
@@ -99,7 +90,7 @@ Options for large schemas and high traffic, all off by default. See
|
|
|
99
90
|
config.schema_cache = Rails.env.production? # cache the built schema in tmp/cache
|
|
100
91
|
config.watch_sdl = Rails.env.development? # reload when a .graphql file changes
|
|
101
92
|
config.persisted_queries = true # Apollo's Automatic Persisted Queries
|
|
102
|
-
config.persisted_queries_store = Rails.cache # where APQ keeps queries (default:
|
|
93
|
+
config.persisted_queries_store = Rails.cache # where APQ keeps queries (default: Rails.cache)
|
|
103
94
|
config.persisted_queries_ttl = 1.week.to_i # how long they live there
|
|
104
95
|
config.persisted_queries_manifest = Rails.root.join('persisted-queries.json') # trusted operations
|
|
105
96
|
config.persisted_queries_only = Rails.env.production? # run nothing else
|
|
@@ -128,17 +119,6 @@ returning `[type, id]`. Defaults to `Lighthouse::GraphQL::GlobalId`, the base64
|
|
|
128
119
|
config.global_id = SignedGlobalIds
|
|
129
120
|
```
|
|
130
121
|
|
|
131
|
-
### `upload_store`
|
|
132
|
-
|
|
133
|
-
Stores the file an [`@upload`](uploads.md) argument carries: any object with
|
|
134
|
-
`call(file, disk:, path:, public:)`, whose return value the argument then holds.
|
|
135
|
-
Defaults to `Lighthouse::GraphQL::UploadStore`, which makes an ActiveStorage blob and
|
|
136
|
-
returns its signed id.
|
|
137
|
-
|
|
138
|
-
```ruby
|
|
139
|
-
config.upload_store = ->(file, path: '/', **) { S3Uploader.put(file, prefix: path) }
|
|
140
|
-
```
|
|
141
|
-
|
|
142
122
|
### `queue_broadcasts`, `broadcast_queue`
|
|
143
123
|
|
|
144
124
|
Whether [`@broadcast`](directives.md#broadcast) triggers its subscription in an
|
data/docs/directives.md
CHANGED
|
@@ -283,16 +283,23 @@ type PostQueries {
|
|
|
283
283
|
|
|
284
284
|
### `@throttle`
|
|
285
285
|
|
|
286
|
-
|
|
287
|
-
(default 60 a minute), counted
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
286
|
+
Rails' `rate_limit` on one field: at most `maxAttempts` calls (its `to:`) every
|
|
287
|
+
`decayMinutes` (its `within:`, default 60 a minute), counted before anything else runs.
|
|
288
|
+
It takes `rate_limit`'s options, and counts as `rate_limit` does: in the controller's
|
|
289
|
+
`cache_store`, under the same key, and instrumented as `rate_limit.action_controller`.
|
|
290
|
+
See [security.md](security.md#rate-limiting).
|
|
291
|
+
|
|
292
|
+
| Argument | `rate_limit`'s | Default |
|
|
293
|
+
| --- | --- | --- |
|
|
294
|
+
| `by:` | `by:`, who the client is: a path in the context, as [`@inject`](resolvers.md#spread-and-inject)'s (`"current_user.id"`) | the client's IP |
|
|
295
|
+
| `with:` | `with:`, the controller's method to call past the limit | `rate_limit`'s: a 429 (it raises `ActionController::TooManyRequests`) |
|
|
296
|
+
| `name:` | `name:`; fields, and the controller's own `rate_limit`, of the same name count together | the field (`Query.x`) |
|
|
297
|
+
| `prefix:` | `scope:` | the controller's path |
|
|
292
298
|
|
|
293
299
|
```graphql
|
|
294
300
|
type Mutation {
|
|
295
301
|
login(email: String!, password: String!): User @throttle(maxAttempts: 5)
|
|
302
|
+
createTag(name: String!): Tag! @throttle(maxAttempts: 20, by: "current_user.id", with: "too_many_requests") @guard @create
|
|
296
303
|
}
|
|
297
304
|
```
|
|
298
305
|
|
|
@@ -584,7 +591,7 @@ order the SDL lists them:
|
|
|
584
591
|
| `@drop` | nothing: the argument is removed |
|
|
585
592
|
| `@hash` | the value hashed with BCrypt (the `bcrypt` gem, as `has_secure_password`) |
|
|
586
593
|
| `@bind(class:, column: "id", with: [], optional: false)` | the model record(s) the value identifies, eager-loading `with`; or what a class's `call(value, context)` returns |
|
|
587
|
-
| `@upload(disk:, path: "/")` |
|
|
594
|
+
| `@upload(disk:, path: "/", public: false)` | the signed id of the ActiveStorage blob the file was stored as, on the app's service `disk` names ([uploads.md](uploads.md)) |
|
|
588
595
|
|
|
589
596
|
```graphql
|
|
590
597
|
type Mutation {
|
data/docs/generators.md
CHANGED
|
@@ -2,51 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
Lighthouse builds on graphql-ruby, and so do its generators: it writes only what
|
|
4
4
|
graphql-ruby has no generator for, or what an SDL-first schema needs differently.
|
|
5
|
-
Every graphql-ruby app's base classes (`Types::BaseObject`,
|
|
6
|
-
`Mutations::BaseMutation`, ...) come from graphql-ruby's
|
|
5
|
+
Every graphql-ruby app's schema class and base classes (`Types::BaseObject`,
|
|
6
|
+
`Resolvers::BaseResolver`, `Mutations::BaseMutation`, ...) come from graphql-ruby's
|
|
7
|
+
own `graphql:install`, and `lighthouse:install` builds on them.
|
|
7
8
|
|
|
8
9
|
## `lighthouse:install`
|
|
9
10
|
|
|
10
11
|
```shell
|
|
12
|
+
bin/rails generate graphql:install # graphql-ruby's, with the options you choose
|
|
11
13
|
bin/rails generate lighthouse:install
|
|
12
14
|
```
|
|
13
15
|
|
|
14
|
-
It
|
|
15
|
-
(
|
|
16
|
+
It works on what graphql-ruby's `graphql:install` wrote, with whichever of its
|
|
17
|
+
options the app chose (`--relay`, the default, `--batch`, `--skip-mutation-root-type`,
|
|
18
|
+
`--schema`, `--directory`, `--api`, ...). When the app has no graphql-ruby schema
|
|
19
|
+
class yet, it runs `graphql:install` first, with graphql-ruby's defaults (and
|
|
20
|
+
`--api` when `config.api_only = true`). Then it adapts what graphql-ruby wrote:
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
| File | What Lighthouse does |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `app/graphql/app_schema.rb` | `class AppSchema < GraphQL::Schema` becomes `class AppSchema < Lighthouse::GraphQL::RbLightHouse.get_schema(options: { base_types: { ... } })`, naming every class graphql-ruby wrote. The rest of the class stays, but the `query(...)` / `mutation(...)` lines (the SDL's root types are built on those classes) and the `resolve_type` stub (Lighthouse resolves types). With `--batch`, `use GraphQL::Dataloader` goes beside `use GraphQL::Batch`, as Lighthouse's directives batch through the Dataloader |
|
|
25
|
+
| `app/graphql/types/query_type.rb`, `mutation_type.rb` | The example `test_field` goes. Relay's `node` / `nodes` stay: the SDL's `Query` is built on `Types::QueryType`, so its `field`s are the schema's too |
|
|
26
|
+
| `app/graphql/types/base_object.rb`, `base_interface.rb`, `base_union.rb`, `base_scalar.rb` | `include Lighthouse::GraphQL::Type`: every type class inheriting from them is Lighthouse's, `Types::QueryType` and `Types::NodeType` included |
|
|
27
|
+
| `app/graphql/mutations/base_mutation.rb` | Kept as graphql-ruby wrote it, a `RelayClassicMutation` (see [resolvers.md](resolvers.md#resolution-by-convention)) |
|
|
28
|
+
| `app/controllers/graphql_controller.rb` | Replaced by one including `Lighthouse::GraphQL::Controller` (`lighthouse_schema AppSchema`), when it is still as graphql-ruby wrote it. One the app changed is kept, and the install says how to serve the schema |
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
And it adds Lighthouse's own:
|
|
24
31
|
|
|
25
|
-
| File | What
|
|
32
|
+
| File | What it is |
|
|
26
33
|
| --- | --- |
|
|
27
|
-
| `
|
|
28
|
-
| `app/controllers/graphql_controller.rb` | Replaced by one including `Lighthouse::GraphQL::Controller` |
|
|
29
|
-
| `app/graphql/types/query_type.rb`, `mutation_type.rb` | Removed: the SDL declares the root types |
|
|
30
|
-
| `app/graphql/mutations/base_mutation.rb` | Made a `GraphQL::Schema::Mutation`: the SDL declares a mutation's arguments, where graphql-ruby's `RelayClassicMutation` takes a single `input:` |
|
|
31
|
-
| `app/graphql/subscriptions/base_subscription.rb` | Written: graphql-ruby has no subscription base. It includes `Lighthouse::GraphQL::Subscription` |
|
|
32
|
-
| `config/initializers/lighthouse.rb` | Written: every [configuration](configuration.md) option, commented out |
|
|
34
|
+
| `config/initializers/lighthouse.rb` | Every [configuration](configuration.md) option, commented out |
|
|
33
35
|
| `graphql/schema.graphql` | A starter schema, unless the folder holds `.graphql` files already |
|
|
34
36
|
| `graphql.config.yml` | IDE configuration, and `.gitignore` entries for the [IDE helper](getting-started.md#ide-support) files |
|
|
37
|
+
| `app/graphql/subscriptions/base_subscription.rb` | With `--subscriptions` only: graphql-ruby has no subscription base. It includes `Lighthouse::GraphQL::Subscription` |
|
|
38
|
+
| `config/routes.rb` | `post "/graphql", to: "graphql#execute"`, when missing |
|
|
35
39
|
|
|
36
40
|
| Option | Effect |
|
|
37
41
|
| --- | --- |
|
|
38
|
-
| `--schema=ApiSchema` |
|
|
42
|
+
| `--schema=ApiSchema` | Which graphql-ruby schema class to adopt, and its name when `graphql:install` has to run |
|
|
39
43
|
| `--sdl-folder=app/schema` | Where the `.graphql` files live (default `graphql`); sets `config.sdl_folder` |
|
|
40
|
-
| `--
|
|
44
|
+
| `--subscriptions` | Write `Subscriptions::BaseSubscription` and name it in `base_types` |
|
|
45
|
+
| `--skip-controller` | Leave graphql-ruby's controller as it is, and add no route — for apps that serve GraphQL themselves |
|
|
41
46
|
| `--skip-ide` | No `graphql.config.yml` or `.gitignore` entries |
|
|
42
|
-
| `--force` | Replace a schema class or controller the app had before |
|
|
43
47
|
|
|
44
|
-
Rerunning it
|
|
45
|
-
|
|
46
|
-
controller, those are kept (Lighthouse replaces only what graphql-ruby wrote in the
|
|
47
|
-
same run), and graphql-ruby's install points that schema at the root types it
|
|
48
|
-
wrote: have the controller call `AppSchema.execute(...)` to serve Lighthouse's
|
|
49
|
-
schema, or pass `--force`.
|
|
48
|
+
Rerunning it changes nothing: a schema class that is Lighthouse's already, a file
|
|
49
|
+
the app has, the route and the `.gitignore` entries are left as they are.
|
|
50
50
|
|
|
51
51
|
## Lighthouse's generators
|
|
52
52
|
|
|
@@ -56,27 +56,29 @@ schema. Each writes into the first namespace configured for its kind (or
|
|
|
56
56
|
|
|
57
57
|
| Generator | Writes |
|
|
58
58
|
| --- | --- |
|
|
59
|
-
| `lighthouse:query LatestPosts` | `Resolvers::LatestPosts < BaseResolver`, which `Query.latestPosts` resolves to by convention |
|
|
60
|
-
| `lighthouse:mutation PublishPost` | `Mutations::PublishPost < BaseMutation`, for `Mutation.publishPost` |
|
|
61
59
|
| `lighthouse:subscription PostUpdated` | `Subscriptions::PostUpdated < BaseSubscription`, with its hooks (and the base, when missing) |
|
|
62
60
|
| `lighthouse:builder Published` | `Builders::Published`, for `@builder(class: "Published")` |
|
|
63
61
|
| `lighthouse:validator CreatePostInput` | `Validators::CreatePostInputValidator`, a `Dry::Validation::Contract` |
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
A subscription's arguments and return type are the SDL's, so the class declares
|
|
64
|
+
neither. When `Subscriptions::BaseSubscription` is missing, `lighthouse:subscription`
|
|
65
|
+
writes it.
|
|
66
|
+
|
|
67
|
+
A resolver or mutation class has no Lighthouse generator: write a
|
|
68
|
+
`Resolvers::BaseResolver` subclass by hand (see [resolvers.md](resolvers.md)), add a
|
|
69
|
+
method to `Types::QueryType`, or run graphql-ruby's `graphql:mutation`.
|
|
69
70
|
|
|
70
71
|
## graphql-ruby's generators in a Lighthouse app
|
|
71
72
|
|
|
72
73
|
| Generator | In a Lighthouse app |
|
|
73
74
|
| --- | --- |
|
|
74
|
-
| `graphql:install` |
|
|
75
|
-
| `graphql:object Post` | **Use it** for a [type class](resolvers.md#type-classes):
|
|
76
|
-
| `graphql:scalar DateTime` | **Use it** for a [scalar](types.md#scalars):
|
|
77
|
-
| `graphql:union SearchResult`, `graphql:interface Authored` | **Use them** when the [default resolution](types.md#the-default) is not enough: add
|
|
75
|
+
| `graphql:install` | The base `lighthouse:install` builds on: run it first with the options you want, or let `lighthouse:install` run it with its defaults |
|
|
76
|
+
| `graphql:object Post` | **Use it** for a [type class](resolvers.md#type-classes): it inherits from `Types::BaseObject`, so it is Lighthouse's; add methods. The `field` lines it writes (from the model's columns, when there is one) are ignored, as the SDL declares the fields: delete them |
|
|
77
|
+
| `graphql:scalar DateTime` | **Use it** for a [scalar](types.md#scalars): its `coerce_input` / `coerce_result` are the ones Lighthouse calls |
|
|
78
|
+
| `graphql:union SearchResult`, `graphql:interface Authored` | **Use them** when the [default resolution](types.md#the-default) is not enough: add a `resolve_type`. Their `possible_types` and `field` lines are ignored |
|
|
78
79
|
| `graphql:enum`, `graphql:input` | Not needed: the SDL declares enums and inputs ([`@enum`](directives.md#enum) gives a value an internal one) |
|
|
79
|
-
| `graphql:mutation
|
|
80
|
-
| `graphql:
|
|
80
|
+
| `graphql:mutation PublishPost` | **Use it** for a code-first mutation: it writes `Mutations::PublishPost` and adds `field :publish_post, mutation: Mutations::PublishPost` to `Types::MutationType`, which the SDL's `Mutation` is built on. The class declares its own arguments and fields, as in graphql-ruby |
|
|
81
|
+
| `graphql:mutation_create` / `_update` / `_delete` | Code-first mutations like `graphql:mutation`'s, whose payload and input are code-first types (`Types::PostType`, `Types::PostInputType`). For a type the SDL declares, use [`@create`, `@update`, `@delete`](mutations.md) |
|
|
82
|
+
| `graphql:relay` | Run by `graphql:install` (`--relay` is its default). On an app installed with `--no-relay`, it adds `Types::NodeType`, `node` / `nodes` and the schema's `id_from_object` / `object_from_id`: add `node: Types::NodeType` to `base_types` by hand. See [relay.md](relay.md#relay-through-graphql-ruby) |
|
|
81
83
|
| `graphql:loader` | A GraphQL::Batch loader, which your own resolver classes may use; Lighthouse's directives batch through graphql-ruby's Dataloader instead |
|
|
82
|
-
| `graphql:detailed_trace` | **Not ready**: it
|
|
84
|
+
| `graphql:detailed_trace` | **Not ready**: it looks for `class AppSchema < GraphQL::Schema`, which a Lighthouse schema class (`< Lighthouse::GraphQL::RbLightHouse.get_schema(...)`) does not match, and stops. Add `use GraphQL::Tracing::DetailedTrace` and `def self.detailed_trace?(query)` to the class body by hand, with graphql-ruby's migration (or `redis:`) |
|