- HTML
-
- if section_count == 0
- if headers.any?
- full_path = "guides/#{context["page"]["path"]}"
- warn("No sections identified for #{full_path} -- make sure it's using `## ...` for section headings.")
- end
- ""
- else
- html
- end
- end
-
- private
-
- def render_table_into_html(html_str, table)
- html_str << ""
- table.each_with_index do |entry, idx|
- if idx == 0
- next # parent reference
- end
- rendered_text, target, child_table = *entry
- html_str << "
"
- html_str << "#{rendered_text}"
- if child_table.any?
- render_table_into_html(html_str, child_table)
- end
- html_str << "
"
- end
- html_str << ""
- end
- end
-end
-
-
-
-Liquid::Template.register_filter(GraphQLSite::APIDoc)
-Liquid::Template.register_tag("api_doc_root", GraphQLSite::APIDocRoot)
-Liquid::Template.register_tag("open_an_issue", GraphQLSite::OpenAnIssue)
-Liquid::Template.register_tag("internal_link", GraphQLSite::InternalLink)
-Liquid::Template.register_tag("table_of_contents", GraphQLSite::TableOfContents)
-Liquid::Template.register_tag('callout', GraphQLSite::CalloutBlock)
-Jekyll::Hooks.register :site, :pre_render do |site|
- section_pages = Hash.new { |h, k| h[k] = [] }
- section_names = []
- site.pages.each do |page|
- this_section = page.data["section"]
- if this_section
- this_section_pages = section_pages[this_section]
- this_section_pages << page
- this_section_pages.sort_by! { |page| page.data["index"] || 100 }
- page.data["section_pages"] = this_section_pages
- section_names << this_section
- end
- end
- section_names.compact!
- section_names.uniq!
- all_sections = []
- section_names.each do |section_name|
- all_sections << {
- "name" => section_name,
- "overview_page" => section_pages[section_name].first,
- }
- end
-
- sorted_section_names = site.pages.find { |p| p.data["title"] == "Guides Index" }.data["sections"].map { |s| s["name"] }
- all_sections.sort_by! { |s| sorted_section_names.index(s["name"]) }
- site.data["all_sections"] = all_sections
-end
-
-module Jekyll
- module Algolia
- module Hooks
- def self.before_indexing_each(record, node, context)
- record = record.dup
- record.delete(:section_pages)
- record
- end
- end
- end
-end
diff --git a/guides/_sass/reset.scss b/guides/_sass/reset.scss
deleted file mode 100644
index 47c6f90962b..00000000000
--- a/guides/_sass/reset.scss
+++ /dev/null
@@ -1,48 +0,0 @@
-/* https://meyerweb.com/eric/tools/css/reset/
- v2.0 | 20110126
- License: none (public domain)
-*/
-
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed,
-figure, figcaption, footer, header, hgroup,
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
- margin: 0;
- padding: 0;
- border: 0;
- font-size: 100%;
- font: inherit;
- vertical-align: baseline;
-}
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
- display: block;
-}
-body {
- line-height: 1;
-}
-ol, ul {
- list-style: none;
-}
-blockquote, q {
- quotes: none;
-}
-blockquote:before, blockquote:after,
-q:before, q:after {
- content: '';
- content: none;
-}
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
diff --git a/guides/_tasks/site.rb b/guides/_tasks/site.rb
deleted file mode 100644
index 3c6cfbabdf6..00000000000
--- a/guides/_tasks/site.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-# frozen_string_literal: true
-require "yard"
-require "webrick"
-
-namespace :apidocs do
- desc "Fetch a gem version from RubyGems, build the docs"
- task :gen_version, [:version] do |t, args|
- # GITHUB_REF comes from GitHub Actions
- version = args[:version] || ENV["GITHUB_REF"] || raise("A version is required")
- puts "Building docs for #{version}"
- # GitHub Actions gives the full tag name
- if version.start_with?("refs/tags/")
- version = version[10..-1]
- end
- if version.start_with?("v")
- version = version[1..-1]
- end
- Dir.mktmpdir do
- puts "Fetching graphql-#{version}"
- system("gem fetch graphql --version=#{version}")
- system("gem unpack graphql-#{version}.gem")
- system("rm graphql-#{version}.gem")
-
- Dir.chdir("graphql-#{version}") do
- # Copy it into gh-pages for publishing
- # and locally for previewing
- push_dest = File.expand_path("../gh-pages/api-doc/#{version}")
- local_dest = File.expand_path("../guides/_site/api-doc/#{version}")
- puts "Creating directories: #{push_dest.inspect}, #{local_dest.inspect}"
- FileUtils.mkdir_p(push_dest)
- FileUtils.mkdir_p(local_dest)
- system("yardoc")
- puts "Copying from #{Dir.pwd}/doc to #{push_dest}"
- copy_entry "doc", push_dest
- puts "Copying from #{Dir.pwd}/doc to #{local_dest}"
- copy_entry "doc", local_dest
- end
- end
- puts "Successfully generated docs for #{version}"
- end
-end
-
-namespace :site do
- desc "View the documentation site locally"
- task serve: [] do # if you need api docs, add `:build_doc` to the list of dependencies
- require "jekyll"
- options = {
- "source" => File.expand_path("guides"),
- "destination" => File.expand_path("guides/_site"),
- "watch" => true,
- "serving" => true
- }
- # Generate the site in server mode.
- puts "Running Jekyll..."
- Jekyll::Commands::Build.process(options)
- Jekyll::Commands::Serve.process(options)
- end
-
- desc "Get the gh-pages branch locally, make sure it's up-to-date"
- task :fetch_latest do
- # Ensure the gh-pages dir exists so we can generate into it.
- puts "Checking for gh-pages dir..."
- unless File.exist?("./gh-pages")
- puts "Creating gh-pages dir..."
- sh "git clone git@github.com:rmosolgo/graphql-ruby gh-pages"
- end
-
- # Ensure latest gh-pages branch history.
- Dir.chdir("gh-pages") do
- sh "git checkout gh-pages"
- sh "git pull origin gh-pages"
- end
- end
-
- desc "Remove all generated HTML (making space to re-generate)"
- task :clean_html do
- # Proceed to purge all files in case we removed a file in this release.
- puts "Cleaning gh-pages directory..."
- purge_exclude = [
- 'gh-pages/.',
- 'gh-pages/..',
- 'gh-pages/.git',
- 'gh-pages/.gitignore',
- 'gh-pages/api-doc',
- ]
-
- FileList["gh-pages/{*,.*}"].exclude(*purge_exclude).each do |path|
- sh "rm -rf #{path}"
- end
- end
-
- desc "Build guides/ into gh-pages/ with Jekyll"
- task :build_html do
- # Copy site to gh-pages dir.
- puts "Building site into gh-pages branch..."
- ENV['JEKYLL_ENV'] = 'production'
- require "jekyll"
- Jekyll::Commands::Build.process({
- "source" => File.expand_path("guides"),
- "destination" => File.expand_path("gh-pages"),
- "sass" => { "style" => "compressed" }
- })
-
- File.write('gh-pages/.nojekyll', "Prevent GitHub from running Jekyll")
- end
-
- desc "Commit new docs"
- task :commit_changes do
- puts "Committing and pushing to GitHub Pages..."
- sha = `git rev-parse HEAD`.strip
- Dir.chdir('gh-pages') do
- system "git status"
- system "git add ."
- system "git status"
- system "git commit --allow-empty -m 'Updating to #{sha}.'"
- end
- end
-
- desc "Push docs to gh-pages branch"
- task :push_commit do
- Dir.chdir('gh-pages') do
- sh "git push origin gh-pages"
- end
- end
-
- desc "Commit the local site to the gh-pages branch and publish to GitHub Pages"
- task publish: [:build_doc, :update_search_index, :fetch_latest, :clean_html, :build_html, :commit_changes, :push_commit]
-
- YARD::Rake::YardocTask.new(:prepare_yardoc)
-
- task build_doc: :prepare_yardoc do
- require_relative "../../lib/graphql/version"
-
- def to_rubydoc_url(path)
- "/api-doc/#{GraphQL::VERSION}/" + path
- .gsub("::", "/") # namespaces
- .sub(/#(.+)$/, "#\\1-instance_method") # instance methods
- .sub(/\.(.+)$/, "#\\1-class_method") # class methods
- end
-
- DOC_TEMPLATE = <<-PAGE
----
-layout: doc_stub
-search: true
-title: %{title}
-url: %{url}
-rubydoc_url: %{url}
-doc_stub: true
----
-
-%{documentation}
-PAGE
-
- puts "Preparing YARD docs @ v#{GraphQL::VERSION} for search index..."
- registry = YARD::Registry.load!(".yardoc")
- files_target = "guides/yardoc"
- FileUtils.rm_rf(files_target)
- FileUtils.mkdir_p(files_target)
-
- # Get docs for all classes and modules
- docs = registry.all(:class, :module)
- docs.each do |code_object|
- begin
- # Skip private classes and modules
- if code_object.visibility == :private
- next
- end
- rubydoc_url = to_rubydoc_url(code_object.path)
- page_content = DOC_TEMPLATE % {
- title: code_object.path,
- url: rubydoc_url,
- documentation: code_object.format.gsub(/-{2,}/, " ").gsub(/^\s+/, ""),
- }
-
- filename = code_object.path.gsub(/\W+/, "_")
- filepath = "guides/yardoc/#{filename}.md"
- File.write(filepath, page_content)
- rescue StandardError => err
- puts "Error on: #{code_object.path}"
- puts err
- puts err.backtrace
- end
- end
- puts "Wrote #{docs.size} YARD docs to #{files_target}."
- end
-
- desc "Update the Algolia search index used for graphql-ruby.org"
- task :update_search_index do
- if !ENV["ALGOLIA_API_KEY"]
- warn("Can't update search index without ALGOLIA_API_KEY; Search will be out-of-date.")
- else
- system("bundle exec jekyll algolia push --source=./guides")
- end
- end
-end
diff --git a/guides/authorization/authorization.md b/guides/authorization/authorization.md
index 474b544b9d7..3f505f89351 100644
--- a/guides/authorization/authorization.md
+++ b/guides/authorization/authorization.md
@@ -1,11 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: Authorization
-desc: During execution, check if the current user has permission to access retrieved objects.
-index: 3
----
+# Authorization
While a query is running, you can check each object to see whether the current user is authorized to interact with that object. If the user is _not_ authorized, you can handle the case with an error.
@@ -62,7 +55,7 @@ class Types::BaseField < GraphQL::Schema::Field
end
```
-For this to work, the base field class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-fields" %}.
+For this to work, the base field class must be [configured with other GraphQL types](/type_definitions/extensions.html#customizing-fields).
#### Argument Authorization
@@ -85,23 +78,23 @@ class Types::BaseArgument < GraphQL::Schema::Argument
end
```
-For this to work, the base argument class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-arguments" %}.
+For this to work, the base argument class must be [configured with other GraphQL types](/type_definitions/extensions.html#customizing-arguments).
## Mutation Authorization
-See {% internal_link "Mutation Authorization", "/mutations/mutation_authorization.html#can-this-user-perform-this-action" %} in the Mutation Guides.
+See [Mutation Authorization](/mutations/mutation_authorization.html#can-this-user-perform-this-action) in the Mutation Guides.
## Enum Value Authorization
-{{ "GraphQL::Schema::EnumValue#authorized?" | api_doc }} is called when client input is received and when the schema returns values to the client.
+[GraphQL::Schema::EnumValue#authorized?](rdoc-ref:GraphQL::Schema::EnumValue#authorized?) is called when client input is received and when the schema returns values to the client.
-For authorizing input, if a value's `#authorized?` method returns false, then a {{ "GraphQL::UnauthorizedEnumValueError" | api_doc }} is raised. It passed to your schema's `.unauthorized_object` hook, where you can handle it another way if you want.
+For authorizing input, if a value's `#authorized?` method returns false, then a [GraphQL::UnauthorizedEnumValueError](rdoc-ref:GraphQL::UnauthorizedEnumValueError) is raised. It passed to your schema's `.unauthorized_object` hook, where you can handle it another way if you want.
-For authorizing return values, if an outgoing value's `#authorized?` method returns false, then a {{ "GraphQL::Schema::Enum::UnresolvedValueError" | api_doc }} is raised, which crashes the query. In this case, you should modify your field or resolver to _not_ return this value to an unauthorized viewer. (In this case, the error isn't returned to the viewer because the viewer can't do anything about it -- it's a developer-facing issue instead.)
+For authorizing return values, if an outgoing value's `#authorized?` method returns false, then a [GraphQL::Schema::Enum::UnresolvedValueError](rdoc-ref:GraphQL::Schema::Enum::UnresolvedValueError) is raised, which crashes the query. In this case, you should modify your field or resolver to _not_ return this value to an unauthorized viewer. (In this case, the error isn't returned to the viewer because the viewer can't do anything about it -- it's a developer-facing issue instead.)
## Handling Unauthorized Objects
-By default, GraphQL-Ruby silently replaces unauthorized objects with `nil`, as if they didn't exist. You can customize this behavior by implementing {{ "Schema.unauthorized_object" | api_doc }} in your schema class, for example:
+By default, GraphQL-Ruby silently replaces unauthorized objects with `nil`, as if they didn't exist. You can customize this behavior by implementing [Schema.unauthorized_object](rdoc-ref:GraphQL::Schema.unauthorized_object) in your schema class, for example:
```ruby
class MySchema < GraphQL::Schema
diff --git a/guides/authorization/can_can_integration.md b/guides/authorization/can_can_integration.md
index 09c3113eb82..214f7d53ed8 100644
--- a/guides/authorization/can_can_integration.md
+++ b/guides/authorization/can_can_integration.md
@@ -1,13 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: CanCan Integration
-desc: Hook up GraphQL to CanCan abilities
-index: 4
-pro: true
----
-
+# CanCan Integration
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [CanCan](https://github.com/CanCanCommunity/cancancan).
@@ -82,13 +73,13 @@ end
### Handling Unauthorized Objects
-When any CanCan check returns `false`, the unauthorized object is passed to {{ "Schema.unauthorized_object" | api_doc }}, as described in {% internal_link "Handling unauthorized objects", "/authorization/authorization#handling-unauthorized-objects" %}.
+When any CanCan check returns `false`, the unauthorized object is passed to [Schema.unauthorized_object](rdoc-ref:GraphQL::Schema.unauthorized_object), as described in [Handling unauthorized objects](/authorization/authorization#handling-unauthorized-objects).
## Scopes
#### ActiveRecord::Relation
-The CanCan integration adds [CanCan's `.accessible_by`](https://github.com/cancancommunity/cancancan/wiki/Fetching-Records) to GraphQL-Ruby's {% internal_link "list scoping", "/authorization/scoping" %}
+The CanCan integration adds [CanCan's `.accessible_by`](https://github.com/cancancommunity/cancancan/wiki/Fetching-Records) to GraphQL-Ruby's [list scoping](/authorization/scoping)
To scope lists of interface or union type, include the integration in your base union class and base interface module _and_ set a base `can_can_action`, if desired:
@@ -193,7 +184,7 @@ class Types::BaseField
end
```
-(See {{ "GraphQL::Schema::Field" | api_doc }} for the different values available for defaults.)
+(See [GraphQL::Schema::Field](rdoc-ref:GraphQL::Schema::Field) for the different values available for defaults.)
### Providing a Custom CanCan Subject
@@ -339,7 +330,7 @@ The method is called with:
Since it's a mutation method, you can also access `context` in that method.
-Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return {% internal_link "errors as data", "/mutations/mutation_errors" %}:
+Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return [errors as data](/mutations/mutation_errors):
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
diff --git a/guides/authorization/overview.md b/guides/authorization/overview.md
index 9e2258707ef..cc035635b20 100644
--- a/guides/authorization/overview.md
+++ b/guides/authorization/overview.md
@@ -1,11 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: Overview
-desc: Overview of GraphQL authorization in general and an intro to the built-in framework.
-index: 0
----
+# Overview
Here's a conceptual approach to GraphQL authorization, followed by an introduction to the built-in authorization framework. Each part of the framework is described in detail in its own guide.
@@ -131,7 +124,7 @@ Despite the advantages of authorization at the application layer, as described a
To accomplish these, you can use GraphQL-Ruby's authorization framework. The framework has three levels, each of which is described in its own guide:
-- {% internal_link "Visibility", "/authorization/visibility" %} hides parts of the GraphQL schema from users who don't have full permission.
-- {% internal_link "Authorization", "/authorization/authorization" %} checks application objects during execution to be sure the user has permission to access them.
+- [Visibility](/authorization/visibility) hides parts of the GraphQL schema from users who don't have full permission.
+- [Authorization](/authorization/authorization) checks application objects during execution to be sure the user has permission to access them.
-Also, [GraphQL::Pro](https://graphql.pro) has integrations for {% internal_link "CanCan", "/authorization/can_can_integration" %} and {% internal_link "Pundit", "/authorization/pundit_integration" %}.
+Also, [GraphQL::Pro](https://graphql.pro) has integrations for [CanCan](/authorization/can_can_integration) and [Pundit](/authorization/pundit_integration).
diff --git a/guides/authorization/pundit_integration.md b/guides/authorization/pundit_integration.md
index 0900df6611c..19a04deac42 100644
--- a/guides/authorization/pundit_integration.md
+++ b/guides/authorization/pundit_integration.md
@@ -1,12 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: Pundit Integration
-desc: Hook up GraphQL to Pundit policies
-index: 4
-pro: true
----
+# Pundit Integration
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [Pundit](https://github.com/varvet/pundit) policies.
@@ -121,11 +113,11 @@ end
#### Handling Unauthorized Objects
-When any Policy method returns `false`, the unauthorized object is passed to {{ "Schema.unauthorized_object" | api_doc }}, as described in {% internal_link "Handling unauthorized objects", "/authorization/authorization#handling-unauthorized-objects" %}.
+When any Policy method returns `false`, the unauthorized object is passed to [Schema.unauthorized_object](rdoc-ref:GraphQL::Schema.unauthorized_object), as described in [Handling unauthorized objects](/authorization/authorization#handling-unauthorized-objects).
## Scopes
-The Pundit integration adds [Pundit scopes](https://github.com/varvet/pundit#scopes) to GraphQL-Ruby's {% internal_link "list scoping", "/authorization/scoping" %} feature. Any list or connection will be scoped. If a scope is missing, the query will crash rather than risk leaking unfiltered data.
+The Pundit integration adds [Pundit scopes](https://github.com/varvet/pundit#scopes) to GraphQL-Ruby's [list scoping](/authorization/scoping) feature. Any list or connection will be scoped. If a scope is missing, the query will crash rather than risk leaking unfiltered data.
To scope lists of interface or union type, include the integration in your base union class and base interface module:
@@ -364,7 +356,7 @@ The method is called with:
Since it's a mutation method, you can also access `context` in that method.
-Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return {% internal_link "errors as data", "/mutations/mutation_errors" %}:
+Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return [errors as data](/mutations/mutation_errors):
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
diff --git a/guides/authorization/scoping.md b/guides/authorization/scoping.md
index acdfbcaaaf3..74a42186c60 100644
--- a/guides/authorization/scoping.md
+++ b/guides/authorization/scoping.md
@@ -1,12 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: Scoping
-desc: Filter lists to match the current viewer and context
-index: 4
----
-
+# Scoping
_Scoping_ is a complementary consideration to authorization. Rather than checking "can this user see this thing?", scoping takes a list of items filters it to the subset which is appropriate for the current viewer and context.
diff --git a/guides/authorization/visibility.md b/guides/authorization/visibility.md
index 2127b298daf..7a117c1c660 100644
--- a/guides/authorization/visibility.md
+++ b/guides/authorization/visibility.md
@@ -1,13 +1,4 @@
----
-layout: guide
-search: true
-section: Authorization
-title: Visibility
-desc: Programmatically hide parts of the GraphQL schema from some users.
-index: 1
-redirect_from:
-- /schema/limiting_visibility
----
+# Visibility
With GraphQL-Ruby, it's possible to _hide_ parts of your schema from some users. This isn't exactly part of the GraphQL spec, but it's roughly within the bounds of the spec.
@@ -110,7 +101,7 @@ class Types::BaseField < GraphQL::Schema::Field
end
```
-For this to work, the base field class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-fields" %}.
+For this to work, the base field class must be [configured with other GraphQL types](/type_definitions/extensions.html#customizing-fields).
## Argument Visibility
@@ -128,7 +119,7 @@ class Types::BaseArgument < GraphQL::Schema::Argument
end
```
-For this to work, the base argument class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-arguments" %}.
+For this to work, the base argument class must be [configured with other GraphQL types](/type_definitions/extensions.html#customizing-arguments).
## Opting Out
@@ -146,7 +137,7 @@ For big schemas, this can be a worthwhile speed-up.
## Migration Notes
-{{ "GraphQL::Schema::Visibility" | api_doc }} is a _new_ implementation of visibility in GraphQL-Ruby. It has some slight differences from the previous implementation ({{ "GraphQL::Schema::Warden" | api_doc }}):
+[GraphQL::Schema::Visibility](rdoc-ref:GraphQL::Schema::Visibility) is a _new_ implementation of visibility in GraphQL-Ruby. It has some slight differences from the previous implementation ([GraphQL::Schema::Warden](rdoc-ref:GraphQL::Schema::Warden)):
- `Visibility` speeds up Rails app boot because it doesn't require all types to be loaded during boot and only loads types as they are used by queries.
- `Visibility` supports predefined, reusable visibility profiles which speeds up queries using complicated `visible?` checks.
diff --git a/guides/changesets/definition.md b/guides/changesets/definition.md
index f46c5eda054..fdf41000b65 100644
--- a/guides/changesets/definition.md
+++ b/guides/changesets/definition.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Changesets
-title: Defining Changesets
-desc: Creating a set of modifications to release in an API version
-index: 2
----
-
-After {% internal_link "installing Changeset integrations", "/changesets/installation" %} in your schema, you can create Changesets which modify parts of the schema. Changesets extend `GraphQL::Enterprise::Changeset` and include a `release` string. Once a Changeset class is defined, it can be referenced with `added_in: ...` or `removed_in: ...` configurations in the schema.
+# Defining Changesets
+
+After [installing Changeset integrations](/changesets/installation) in your schema, you can create Changesets which modify parts of the schema. Changesets extend `GraphQL::Enterprise::Changeset` and include a `release` string. Once a Changeset class is defined, it can be referenced with `added_in: ...` or `removed_in: ...` configurations in the schema.
__Note:__ Before GraphQL-Enterprise 1.3.0, Changesets were configured with `modifies ...` blocks. These blocks are still supported and you can find the documentation for that API [on GitHub](https://github.com/rmosolgo/graphql-ruby/blob/v2.0.22/guides/changesets/definition.md).
@@ -25,7 +16,7 @@ class Changesets::DeprecateRecipeTags < GraphQL::Enterprise::Changeset
end
```
-Additionally, Changesets must be {% internal_link "released", "/changesets/releases" %} for their changes to be published.
+Additionally, Changesets must be [released](/changesets/releases) for their changes to be published.
## Publishing with `added_in:`
@@ -90,7 +81,7 @@ See below for the different kind of modifications you can make in a changeset:
### Fields
-To add or redefine a field, use `field(..., added_in: ...)`, including all configuration values for the new implementation (see {{ "GraphQL::Schema::Field#initialize" | api_doc }}). The definition given here will override the previous definition (if there was one) whenever this Changeset applies.
+To add or redefine a field, use `field(..., added_in: ...)`, including all configuration values for the new implementation (see the [GraphQL::Schema::Field](rdoc-ref:GraphQL::Schema::Field) API). The definition given here will override the previous definition (if there was one) whenever this Changeset applies.
```ruby
class Types::Recipe < Types::BaseObject
@@ -297,4 +288,4 @@ end
Besides observability, you can use a runtime check when a resolver needs to pick a different behavior depending on the API version.
-After defining a changeset, add it to the schema to {% internal_link "release it", "/changesets/releases" %}.
+After defining a changeset, add it to the schema to [release it](/changesets/releases).
diff --git a/guides/changesets/installation.md b/guides/changesets/installation.md
index b4e004211c9..26907ca7fde 100644
--- a/guides/changesets/installation.md
+++ b/guides/changesets/installation.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Changesets
-title: Installing Changesets
-desc: Adding Changesets to your schema
-index: 1
----
+# Installing Changesets
Changesets require some updates to the schema (to define changesets) and some updates to your controller (to receive version headers from clients).
@@ -60,7 +51,7 @@ To get started with [GraphQL-Enterprise](https://graphql.pro/enterprise) Changes
Also, make sure that your `BaseUnion` and `BaseInterface` have `type_membership_class(Types::BaseTypeMembership)` configured in it. (`TypeMembership`s are used by GraphQL-Ruby to link object types to the union types they belong to and the interfaces they implement. By using a custom type membership class, you can make objects belong (or _not_ belong) to unions or interfaces, depending on the API version.)
-Once those integrations are set up, you're ready to {% internal_link "write a changeset", "/changesets/definition" %} and start {% internal_link "releasing API versions", "/changesets/releases" %}!
+Once those integrations are set up, you're ready to [write a changeset](/changesets/definition) and start [releasing API versions](/changesets/releases)!
## Controller Setup
@@ -83,4 +74,4 @@ In the example above, `API-Version: ...` will be parsed from the incoming reques
If `context[:changeset_version]` is `nil`, then _no_ changesets will apply to that request.
-Now that Changesets are installed, read on to {% internal_link "define some changesets", "/changesets/definition" %}.
+Now that Changesets are installed, read on to [define some changesets](/changesets/definition).
diff --git a/guides/changesets/overview.md b/guides/changesets/overview.md
index b391429f465..571db861254 100644
--- a/guides/changesets/overview.md
+++ b/guides/changesets/overview.md
@@ -1,14 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Changesets
-title: API Versioning for GraphQL-Ruby
-desc: Evolve your schema over time, feature-by-feature
-index: 0
----
-
+# API Versioning for GraphQL-Ruby
Out-of-the-box, GraphQL is [versionless by design](https://graphql.org/learn/schema-design/). GraphQL's openness to extension paves the way for continuously expanding and improving an API. You can _always_ add new fields, new arguments, and new types to implement new features and customize existing behavior.
@@ -47,6 +37,6 @@ Then, only clients requesting API versions _before_ this changeset would be abl
To start using Changesets, read on:
-- {% internal_link "Installing Changesets", "/changesets/installation" %}
-- {% internal_link "Writing Changesets", "/changesets/definition" %}
-- {% internal_link "Releasing Changesets", "/changesets/releases" %}
+- [Installing Changesets](/changesets/installation)
+- [Writing Changesets](/changesets/definition)
+- [Releasing Changesets](/changesets/releases)
diff --git a/guides/changesets/releases.md b/guides/changesets/releases.md
index cba13722310..afe401b1a07 100644
--- a/guides/changesets/releases.md
+++ b/guides/changesets/releases.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Changesets
-title: Releasing Changesets
-desc: Associating changes to version numbers
-index: 3
----
+# Releasing Changesets
To be available to clients, Changesets added to the schema with `use GraphQL::Enterprise::Changeset::Release changesets_dir: "..."`:
@@ -24,11 +15,11 @@ end
This attaches each Changeset defined in `app/graphql/changesets/*.rb` to the schema. (It assumes Rails conventions, where an underscored file like `app/graphql/changesets/add_some_feature.rb` contains a class like `Changesets::AddSomeFeature`.)
-{% callout warning %}
+> **Warning:**
+>
+> Add `GraphQL::Enterprise::Changeset::Release` _before_ hooking up your root `query(...)`, `mutation(...)`, and `subscription(...)` types. Otherwise, the schema may not find links to types in new schema versions.
+>
-Add `GraphQL::Enterprise::Changeset::Release` _before_ hooking up your root `query(...)`, `mutation(...)`, and `subscription(...)` types. Otherwise, the schema may not find links to types in new schema versions.
-
-{% endcallout %}
Alternatively, Changesets can be explicitly attached using `changesets: [...]`, for example:
@@ -46,7 +37,7 @@ Only changesets in the directory (or in the array) will be shown to clients. The
## Inspecting Releases
-To preview releases, you can create schema dumps by passing `context: { changeset_version: ... }` to {{ "Schema.to_definition" | api_doc }}.
+To preview releases, you can create schema dumps by passing `context: { changeset_version: ... }` to [Schema.to_definition](rdoc-ref:GraphQL::Schema.to_definition).
For example, to see how the schema looks with `API-Version: 2021-06-01`:
@@ -56,7 +47,7 @@ schema_sdl = MyAppSchema.to_definition(context: { changeset_version: "2021-06-01
puts schema_sdl
```
-To make sure schema versions don't change unexpectedly, use the techniques described in the {% internal_link "Schema structure guide", "/testing/schema_structure" %}.
+To make sure schema versions don't change unexpectedly, use the techniques described in the [Schema structure guide](/testing/schema_structure).
### Introspection Methods
diff --git a/guides/css/main.scss b/guides/css/main.scss
deleted file mode 100644
index a4d980d0416..00000000000
--- a/guides/css/main.scss
+++ /dev/null
@@ -1,747 +0,0 @@
----
----
-
-@use "reset";
-
-$brand-color: #a5152a;
-$dark-theme-brand-color: #e5534b;
-$brand-color-light: #ed8090;
-$brand-color-extralight: #f9e8ee;
-$dark-theme-brand-color-extralight: #262324;
-
-$experimental-color: #91812f;
-$experimental-background: hsla(50, 100%, 32%, 0.15);
-
-$pro-color: #406db5;
-$pro-background: hsla(217, 100%, 29%, 0.15);
-
-$enterprise-color: #238c44;
-$enterprise-background: hsla(135, 97%, 25%, 0.15);
-
-$dark-theme-code-border: #aaaaaa;
-$code-border: #d6d6d6;
-$dark-theme-code-background: #1e1b1b;
-$code-background: #fafafa;
-$dark-theme-code-color: #b5b5b5;
-$code-color: #777777;
-$code-border-radius: 2px;
-
-$muted-color: #777777;
-$subtle-color: #aaaaaa;
-$font: 'Rubik', sans-serif;
-$code-font: 'Monaco', monospace;
-
-$faint-color: #f0f0f0;
-$dark-theme-faint-color: #6a6969;
-
-$font-color: black;
-$dark-theme-font-color: #dbdbdb;
-
-$background-color: #fafafa;
-$dark-theme-background-color: #422e2e;
-
-$container-color: white;
-$dark-theme-container-color: #424242;
-
-body {
- font-family: $font;
- background: $background-color;
- .dark-theme-button::after {
- content: "☀"
- }
-}
-
-body.dark-theme {
- background: $dark-theme-code-background;
- color: $dark-theme-font-color;
- .dark-theme-button::after {
- content: "☽"
- }
-}
-
-strong, b {
- font-weight: bold;
-}
-
-// Algolia highlights:
-.ais-Highlight {
- font-style: normal;
- font-weight: bold;
-}
-
-.dark-theme {
- .header {
- background: $dark-theme-container-color;
- box-shadow: 0px 0px 10px 0px black;
- .nav a:hover {
- color: $font-color;
- background-color: $dark-theme-brand-color;
- }
- }
-}
-.header {
- box-shadow: 0px 0px 10px 0px #d6d6d6;
- z-index: 1;
- position: relative;
- background: $container-color;
- .nav {
- $height: 30px;
- $margin: 10px;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- $fade-time: 0.2s;
-
- .nav-links {
- margin-left: auto;
- display: flex;
- }
-
- .img-link {
- transition: background $fade-time;
-
- img {
- transition: filter $fade-time;
- transition: -webkit-filter $fade-time;
- filter: brightness(1) invert(0);
- -webkit-filter: brightness(1) invert(0);
- }
-
- &:hover {
- img {
- -webkit-filter: brightness(0) invert(1);
- filter: brightness(0) invert(1);
- }
- }
- }
-
- img {
- height: $height;
- width: auto;
- margin: $margin;
- }
-
- a, span {
- transition: background-color $fade-time;
- transition: color $fade-time;
- padding: $margin;
- height: $height;
- display: flex;
- align-items: center;
- text-decoration: none;
- &:hover {
- background-color: $brand-color;
- color: white;
- }
- }
- }
-}
-
-.header-container {
- margin: 0px 20px 0px 20px;
-}
-
-.container {
- max-width: 1200px;
- margin: 0px auto;
- padding: 10px 20px;
- background: $container-color;
- &.fullwidth {
- max-width: 100%;
- margin: 0px 20px 0px 20px;
- }
-}
-
-.dark-theme {
- .container {
- background: $dark-theme-container-color;
- }
-}
-
-.callout {
- padding: 20px 20px 10px 20px;
- margin: 20px;
- border: 2px;
- border-radius: 10px;
- .heading {
- font-size: 20px;
- font-weight: bold;
- margin-bottom: 20px;
- }
-
- &.callout-warning {
- background-color: rgba(255, 217, 0, 0.2);
- border-color: rgba(255, 217, 0, 0.5);
- }
-}
-
-pre {
- font-family: $code-font;
- padding: 0.5rem;
- border: 1px solid $code-border;
- border-radius: $code-border-radius;
- background-color: $code-background;
- margin: 10px 0px;
- overflow-x: auto;
- line-height: 1.4rem;
-}
-
-.dark-theme {
- pre {
- background-color: $dark-theme-code-background;
- border: 1px solid $dark-theme-code-border;
- }
-}
-
-p, li {
- line-height: 1.3rem;
-}
-
-li {
- margin-left: 15px;
- margin-top: 5px
-}
-
-p, ul {
- margin-bottom: 20px;
-}
-
-ul {
- list-style-type: disc;
- list-style-position: outside;
-}
-
-ol {
- list-style: decimal;
- margin-left: 5px;
-}
-
-code {
- font-family: $code-font;
- color: $code-color;
- font-weight: 400;
-}
-.dark-theme code {
- color: $dark-theme-code-color;
-}
-.code .line-numbers {
- display: none;
-}
-
-
-.dark-theme a {
- color: $dark-theme-brand-color;
- border-color: $dark-theme-brand-color;
- code {
- color: $dark-theme-brand-color;
- }
-}
-
-a {
- color: $brand-color;
- border-color: $brand-color;
- text-decoration: none;
- code {
- color: $brand-color;
- }
-}
-
-a:hover, a:hover code {
- text-decoration: underline;
-}
-
-#readme img {
- display: none;
-}
-
-.guide-container {
- a.img-link {
- background: none;
- &:hover {
- background: none;
- }
- img {
- box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
- transition: all 0.3s cubic-bezier(.25,.8,.25,1);
- max-height: 300px;
- max-width: 100%;
- &:hover {
- box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
- }
- }
- }
-}
-
-.cell {
- overflow-x: scroll;
-}
-
-.guides-toc {
- ul {
- list-style: none;
- display: flex;
- flex-wrap: wrap;
- }
-
- li {
- padding-bottom: 10px;
- padding-right: 10px;
- }
-}
-
-
-.guides {
- .guide-desc {
- color: $muted-color;
- margin-left: 5px;
- }
-
- ul {
- margin-left: 10px;
- list-style: none;
- }
-}
-
-@mixin doc-header($color, $background-color) {
- background-color: $background-color;
- color: $color;
- border-radius: $code-border-radius;
- padding: 10px 10px 10px 10px;
- margin-bottom: 10px;
- border: 1px solid $color;
- p {
- margin: 0px;
- padding: 0px;
- }
- a {
- color: $color;
- text-decoration: underline;
- &:hover {
- background-color: $color;
- color: $background-color;
- }
- }
-}
-
-.experimental-header {
- @include doc-header($experimental-color, $experimental-background);
-}
-
-.pro-header {
- @include doc-header($pro-color, $pro-background);
-}
-
-.enterprise-header {
- @include doc-header($enterprise-color, $enterprise-background);
-}
-
-.dark-theme .guide-footer {
- background-color: $dark-theme-brand-color-extralight;
-}
-
-.guide-footer {
- background: $brand-color-extralight;
- margin: 25px 0px 0px 0px;
- padding: 10px;
- border-radius: $code-border-radius;
-}
-
-
-.dark-theme {
- .hero {
- .hero-part {
- &.shaded {
- background: $dark-theme-faint-color;
- }
-
- h2 {
- color: $dark-theme-brand-color;
- text-shadow: $dark-theme-background-color 1px 1px 1px;
- }
- }
- }
-}
-
-.hero {
- display: flex;
- flex-direction: column;
- justify-content: space-around;
- .hero-title {
- display: flex;
- justify-content: center;
- align-items: center;
-
- img, h1 {
- margin: 20px 10px 30px 10px;
- }
- }
-
- .hero-subtitle {
- padding: 10px 0px;
- p {
- margin: 5px auto;
- text-align: center;
- }
- }
-
- .hero-part {
- display: flex;
- justify-content: space-between;
- flex-wrap: wrap;
-
- &.shaded {
- background: $faint-color;
- }
-
- h2 {
- color: $brand-color;
- text-shadow: #cccccc 1px 1px 1px;
- font-size: 1.4em;
- }
-
- .hero-feature {
- padding: 15px;
- flex-basis: calc(50% - 60px);
- flex-grow: 1;
- }
- }
-}
-
-h1, h2, h3, h4, h5 {
- margin: 25px 0px 15px 0px;
- a {
- text-decoration: none;
- }
-}
-
-.guide-header {
- margin-bottom: 15px;
-}
-
-h1 { font-size: 1.5rem; }
-h2 { font-size: 1.3rem; }
-h3 { font-size: 1.2rem; }
-h4 { font-size: 1.1rem; }
-h5 { font-size: 1.05rem; }
-em { font-style: italic; }
-
-table {
- width: 100%;
- margin: 0px 0px 15px 0px;
- thead {
- text-align: left;
- border-bottom: 1px solid $subtle-color;
- }
- td, th {
- padding: 5px 10px 5px 0px;
- }
-}
-
-.dark-theme {
- .search-input {
- background: $dark-theme-code-background;
- color: $dark-theme-font-color;
- }
- .search-results-container {
- background-color: $dark-theme-background-color;
- #search-results {
- .search-result {
- &:focus, &:hover {
- background-color: $dark-theme-container-color;
- border-bottom-color: $dark-theme-brand-color;
- .search-title {
- color: $dark-theme-brand-color;
- }
- }
- .search-category {
- border: 1px solid $dark-theme-brand-color;
- color: $dark-theme-brand-color;
- }
- }
- }
- }
-}
-.search-input {
- font-size: 1em;
- padding: 5px;
- margin: 10px;
- border: 1px solid $subtle-color;
- border-radius: 3px;
-}
-
-.search-results-container {
- $bg: #eaeaea;
- $bg-highlight: #f9f9f9;
- background-color: $bg;
-
- #search-results {
- $fade-time: 0.1s;
- display: flex;
- flex-direction: column;
- max-width: 1040px;
- margin: 0 auto;
- .search-result {
- text-decoration: none;
- color: $font-color;
- padding: 6px 10px 0px 6px;
- line-height: 18px;
- border-bottom: 2px solid transparent;
- transition: border-bottom-color $fade-time;
-
- .search-title {
- font-weight: bold;
- margin-right: 8px;
- transition: color $fade-time;
- }
-
- .search-preview {
- color: $subtle-color;
- }
- .search-category {
- border: 1px solid $brand-color;
- border-radius: 3px;
- margin: 0 8px 0 0;
- padding: 3px;
- font-size: 0.7em;
- color: $brand-color;
- position: relative;
- top: -3px;
- }
-
- &:focus, &:hover {
- outline: none;
- background-color: $bg-highlight;
- border-bottom-color: $brand-color;
- .search-title {
- color: $brand-color;
- }
- }
- }
- }
-}
-
-.dark-theme ul.breadcrumb .jump-to-select {
- color: $dark-theme-brand-color;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='292.4' height='292.4'%3E%3Cpath fill='%23e5534b' d='M287 69.4a17.6 17.6 0 0 0-13-5.4H18.4c-5 0-9.3 1.8-12.9 5.4A17.6 17.6 0 0 0 0 82.2c0 5 1.8 9.3 5.4 12.9l128 127.9c3.6 3.6 7.8 5.4 12.8 5.4s9.2-1.8 12.8-5.4L287 95c3.5-3.5 5.4-7.8 5.4-12.8 0-5-1.9-9.2-5.5-12.8z'/%3E%3C/svg%3E");
-}
-
-ul.breadcrumb {
- color: $muted-color;
-
- li {
- display: inline;
- list-style: none;
- margin: 0;
- }
- li:before {
- content: "»";
- margin: 0px 4px 0px 2px;
- }
- li:first-child:before {
- content: "";
- margin: 0;
- }
-
- .jump-to-select {
- box-sizing: border-box;
- -moz-appearance: none;
- -webkit-appearance: none;
- appearance: none;
- padding: 5px 20px 5px 5px;
- border: 1px solid $code-border;
- border-radius: 5px;
- background-color: transparent;
- color: $brand-color;
- font-size: 16px;
- font-weight: 500;
- line-height: 1.3;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='292.4' height='292.4'%3E%3Cpath fill='%23a5152a' d='M287 69.4a17.6 17.6 0 0 0-13-5.4H18.4c-5 0-9.3 1.8-12.9 5.4A17.6 17.6 0 0 0 0 82.2c0 5 1.8 9.3 5.4 12.9l128 127.9c3.6 3.6 7.8 5.4 12.8 5.4s9.2-1.8 12.8-5.4L287 95c3.5-3.5 5.4-7.8 5.4-12.8 0-5-1.9-9.2-5.5-12.8z'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right 8px center;
- background-size: 9px;
-
- cursor: default;
-
- &:hover {
- border-color: #777;
- }
-
- &:focus {
- border-color: #999;
- box-shadow: 0 0 1px 2px #6db4ff;
- outline: none;
- }
-
-
- option {
- color: black;
- }
- }
-}
-
-
-.dark-theme {
- .table-of-contents {
- background: $dark-theme-code-background;
- }
-}
-
-.table-of-contents {
- float: right;
- border: 1px solid $subtle-color;
- border-radius: 3px;
- padding: 15px;
- margin: 0 10px 10px 10px;
- width: 300px;
- background: $code-background;
- .contents-header {
- margin: 0 0 5px 20px;
- }
- .contents-list {
- margin: 0;
- list-style: decimal;
- padding-left: 5px;
- .contents-entry {
- &::marker {
- color: $muted-color;
- }
-
- .contents-entry {
- list-style: none;
- }
- }
- }
-}
-
-/* pygments CSS, github theme */
-.highlight .hll { background-color: #ffffcc }
-.highlight .c { color: #999988; font-style: italic } /* Comment */
-.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
-.highlight .k { color: #000000; font-weight: bold } /* Keyword */
-.highlight .o { color: #000000; font-weight: bold } /* Operator */
-.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
-.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
-.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
-.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #aa0000 } /* Generic.Error */
-.highlight .gh { color: #999999 } /* Generic.Heading */
-.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
-.highlight .go { color: #888888 } /* Generic.Output */
-.highlight .gp { color: #555555 } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
-.highlight .gt { color: #aa0000 } /* Generic.Traceback */
-.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
-.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
-.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
-.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
-.highlight .m { color: #009999 } /* Literal.Number */
-.highlight .s { color: #d01040 } /* Literal.String */
-.highlight .na { color: #008080 } /* Name.Attribute */
-.highlight .nb { color: #0086B3 } /* Name.Builtin */
-.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
-.highlight .no { color: #008080 } /* Name.Constant */
-.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
-.highlight .ni { color: #800080 } /* Name.Entity */
-.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
-.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
-.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */
-.highlight .nn { color: #555555 } /* Name.Namespace */
-.highlight .nt { color: #000080 } /* Name.Tag */
-.highlight .nv { color: #008080 } /* Name.Variable */
-.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mf { color: #009999 } /* Literal.Number.Float */
-.highlight .mh { color: #009999 } /* Literal.Number.Hex */
-.highlight .mi { color: #009999 } /* Literal.Number.Integer */
-.highlight .mo { color: #009999 } /* Literal.Number.Oct */
-.highlight .sb { color: #d01040 } /* Literal.String.Backtick */
-.highlight .sc { color: #d01040 } /* Literal.String.Char */
-.highlight .sd { color: #d01040 } /* Literal.String.Doc */
-.highlight .s2 { color: #d01040 } /* Literal.String.Double */
-.highlight .se { color: #d01040 } /* Literal.String.Escape */
-.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */
-.highlight .si { color: #d01040 } /* Literal.String.Interpol */
-.highlight .sx { color: #d01040 } /* Literal.String.Other */
-.highlight .sr { color: #009926 } /* Literal.String.Regex */
-.highlight .s1 { color: #d01040 } /* Literal.String.Single */
-.highlight .ss { color: #990073 } /* Literal.String.Symbol */
-.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
-.highlight .vc { color: #008080 } /* Name.Variable.Class */
-.highlight .vg { color: #008080 } /* Name.Variable.Global */
-.highlight .vi { color: #008080 } /* Name.Variable.Instance */
-.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
-
-
-.dark-theme {
- .highlight .hll { background-color: #49483e }
- pre.highlight { background: #272822; color: #f8f8f2 }
- .highlight .c { color: #75715e } /* Comment */
- .highlight .err { color: #960050; background-color: #1e0010 } /* Error */
- .highlight .k { color: #66d9ef } /* Keyword */
- .highlight .l { color: #ae81ff } /* Literal */
- .highlight .n { color: #f8f8f2 } /* Name */
- .highlight .o { color: #f92672 } /* Operator */
- .highlight .p { color: #f8f8f2 } /* Punctuation */
- .highlight .ch { color: #75715e } /* Comment.Hashbang */
- .highlight .cm { color: #75715e } /* Comment.Multiline */
- .highlight .cp { color: #75715e } /* Comment.Preproc */
- .highlight .cpf { color: #75715e } /* Comment.PreprocFile */
- .highlight .c1 { color: #75715e } /* Comment.Single */
- .highlight .cs { color: #75715e } /* Comment.Special */
- .highlight .gd { color: #f92672; background-color: #5e4343; } /* Generic.Deleted */
- .highlight .ge { font-style: italic } /* Generic.Emph */
- .highlight .gi { color: #a6e22e; background-color: #475547; } /* Generic.Inserted */
- .highlight .gs { font-weight: bold } /* Generic.Strong */
- .highlight .gu { color: #75715e } /* Generic.Subheading */
- .highlight .kc { color: #66d9ef } /* Keyword.Constant */
- .highlight .kd { color: #66d9ef } /* Keyword.Declaration */
- .highlight .kn { color: #f92672 } /* Keyword.Namespace */
- .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
- .highlight .kr { color: #66d9ef } /* Keyword.Reserved */
- .highlight .kt { color: #66d9ef } /* Keyword.Type */
- .highlight .ld { color: #e6db74 } /* Literal.Date */
- .highlight .m { color: #ae81ff } /* Literal.Number */
- .highlight .s { color: #e6db74 } /* Literal.String */
- .highlight .na { color: #a6e22e } /* Name.Attribute */
- .highlight .nb { color: #f8f8f2 } /* Name.Builtin */
- .highlight .nc { color: #a6e22e } /* Name.Class */
- .highlight .no { color: #66d9ef } /* Name.Constant */
- .highlight .nd { color: #a6e22e } /* Name.Decorator */
- .highlight .ni { color: #f8f8f2 } /* Name.Entity */
- .highlight .ne { color: #a6e22e } /* Name.Exception */
- .highlight .nf { color: #a6e22e } /* Name.Function */
- .highlight .nl { color: #f8f8f2 } /* Name.Label */
- .highlight .nn { color: #f8f8f2 } /* Name.Namespace */
- .highlight .nx { color: #a6e22e } /* Name.Other */
- .highlight .py { color: #f8f8f2 } /* Name.Property */
- .highlight .nt { color: #f92672 } /* Name.Tag */
- .highlight .nv { color: #f8f8f2 } /* Name.Variable */
- .highlight .ow { color: #f92672 } /* Operator.Word */
- .highlight .w { color: #f8f8f2 } /* Text.Whitespace */
- .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
- .highlight .mf { color: #ae81ff } /* Literal.Number.Float */
- .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
- .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
- .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
- .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
- .highlight .sc { color: #e6db74 } /* Literal.String.Char */
- .highlight .sd { color: #e6db74 } /* Literal.String.Doc */
- .highlight .s2 { color: #e6db74 } /* Literal.String.Double */
- .highlight .se { color: #ae81ff } /* Literal.String.Escape */
- .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
- .highlight .si { color: #e6db74 } /* Literal.String.Interpol */
- .highlight .sx { color: #e6db74 } /* Literal.String.Other */
- .highlight .sr { color: #e6db74 } /* Literal.String.Regex */
- .highlight .s1 { color: #e6db74 } /* Literal.String.Single */
- .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
- .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
- .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
- .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
- .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
- .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
-}
diff --git a/guides/dataloader/adopting.md b/guides/dataloader/adopting.md
index b7042b0e352..fa565d5ed0b 100644
--- a/guides/dataloader/adopting.md
+++ b/guides/dataloader/adopting.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Dataloader vs. GraphQL-Batch
-desc: Comparing and Contrasting Batch Loading Options
-index: 3
----
-
-{{ "GraphQL::Dataloader" | api_doc }} solves the same problem as [`GraphQL::Batch`](https://github.com/shopify/graphql-batch). There are a few major differences between the modules:
+# Dataloader vs. GraphQL-Batch
+
+[GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) solves the same problem as [`GraphQL::Batch`](https://github.com/shopify/graphql-batch). There are a few major differences between the modules:
- __Concurrency Primitive:__ GraphQL-Batch uses `Promise`s from [`promise.rb`](https://github.com/lgierth/promise.rb); GraphQL::Dataloader uses Ruby's [`Fiber` API](https://ruby-doc.org/core-3.0.0/Fiber.html). These primitives dictate how batch loading code is written (see below for comparisons).
diff --git a/guides/dataloader/async_dataloader.md b/guides/dataloader/async_dataloader.md
index f725602c9a2..1a7849c7371 100644
--- a/guides/dataloader/async_dataloader.md
+++ b/guides/dataloader/async_dataloader.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Async Source Execution
-desc: Using AsyncDataloader to fetch external data in parallel
-index: 5
----
+# Async Source Execution
-`AsyncDataloader` will run {{ "GraphQL::Dataloader::Source#fetch" | api_doc }} calls in parallel, so that external service calls (like database queries or network calls) don't have to wait in a queue.
+`AsyncDataloader` will run [GraphQL::Dataloader::Source#fetch](rdoc-ref:GraphQL::Dataloader::Source#fetch) calls in parallel, so that external service calls (like database queries or network calls) don't have to wait in a queue.
To use `AsyncDataloader`, hook it up in your schema _instead of_ `GraphQL::Dataloader`:
@@ -22,11 +15,11 @@ __Also__, add [the `async` gem](https://github.com/socketry/async) to your proje
bundle add async
```
-Now, {{ "GraphQL::Dataloader::AsyncDataloader" | api_doc }} will create `Async::Task` instances instead of plain `Fiber`s and the `async` gem will manage parallelism.
+Now, [GraphQL::Dataloader::AsyncDataloader](rdoc-ref:GraphQL::Dataloader::AsyncDataloader) will create `Async::Task` instances instead of plain `Fiber`s and the `async` gem will manage parallelism.
For a demonstration of this behavior, see: [https://github.com/rmosolgo/rails-graphql-async-demo](https://github.com/rmosolgo/rails-graphql-async-demo)
-_You can also implement {% internal_link "manual parallelism", "/dataloader/parallelism" %} using `dataloader.yield`._
+_You can also implement [manual parallelism](/dataloader/parallelism) using `dataloader.yield`._
## Rails
@@ -40,7 +33,7 @@ end
```
### ActiveRecord Connections
-You can use Dataloader's {% internal_link "Fiber lifecycle hooks", "/dataloader/dataloader#fiber-lifecycle-hooks" %} to improve ActiveRecord connection handling:
+You can use Dataloader's [Fiber lifecycle hooks](/dataloader/dataloader#fiber-lifecycle-hooks) to improve ActiveRecord connection handling:
- In Rails < 7.2, connections are not reused when a Fiber exits; instead, they're only reused when a request or background job finishes. You can add manual `release_connection` calls to improve this.
- With `isolation_level = :fiber`, new Fibers don't inherit `connected_to ...` settings from their parent fibers.
@@ -77,4 +70,4 @@ Modify the example according to your database configuration and abstract class h
## Other Options
-You can also manually implement parallelism with Dataloader. See the {% internal_link "Dataloader Parallelism", "/dataloader/parallelism" %} guide for details.
+You can also manually implement parallelism with Dataloader. See the [Dataloader Parallelism](/dataloader/parallelism) guide for details.
diff --git a/guides/dataloader/dataloader.md b/guides/dataloader/dataloader.md
index bde06aba0f4..d91eeb2b4b5 100644
--- a/guides/dataloader/dataloader.md
+++ b/guides/dataloader/dataloader.md
@@ -1,22 +1,15 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Dataloader
-desc: The Dataloader orchestrates Fibers and Sources
-index: 2
----
-
-{{ "GraphQL::Dataloader" | api_doc }} instances are created for each query (or multiplex) and they:
-
-- Cache {% internal_link "Source", "/dataloader/sources" %} instances for the duration of GraphQL execution
+# Dataloader
+
+[GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) instances are created for each query (or multiplex) and they:
+
+- Cache [Source](/dataloader/sources) instances for the duration of GraphQL execution
- Run pending Fibers to resolve data requirements and continue GraphQL execution
During a query, you can access the dataloader instance with:
-- {{ "GraphQL::Query::Context#dataloader" | api_doc }} (`context.dataloader`, anywhere that query context is available)
-- {{ "GraphQL::Schema::Object#dataloader" | api_doc }} (`dataloader` inside a resolver method)
-- {{ "GraphQL::Schema::Resolver#dataloader" | api_doc }} (`dataloader` inside `def resolve` of a Resolver, Mutation, or Subscription class.)
+- [GraphQL::Query::Context#dataloader](rdoc-ref:GraphQL::Query::Context#dataloader) (`context.dataloader`, anywhere that query context is available)
+- [GraphQL::Schema::Object#dataloader](rdoc-ref:GraphQL::Schema::Object#dataloader) (`dataloader` inside a resolver method)
+- [GraphQL::Schema::Resolver#dataloader](rdoc-ref:GraphQL::Schema::Resolver#dataloader) (`dataloader` inside `def resolve` of a Resolver, Mutation, or Subscription class.)
## Fiber Lifecycle Hooks
@@ -37,6 +30,6 @@ Then, use your customized dataloader instead of the built-in one:
end
```
-- __{{ "GraphQL::Dataloader#get_fiber_variables" | api_doc }}__ is called before creating a Fiber. By default, it returns a hash containing the parent Fiber's variables (from `Thread.current[...]`). You can add to this hash in your own implementation of this method.
-- __{{ "GraphQL::Dataloader#set_fiber_variables" | api_doc }}__ is called inside the new Fiber. It's passed the hash returned from `get_fiber_variables`. You can use this method to initialize "global" state inside the new Fiber.
-- __{{ "GraphQL::Dataloader#cleanup_fiber" | api_doc }}__ is called just before a Dataloader Fiber exits. You can use this methods to teardown any state that you prepared in `set_fiber_variables`.
+- __[GraphQL::Dataloader#get_fiber_variables](rdoc-ref:GraphQL::Dataloader#get_fiber_variables)__ is called before creating a Fiber. By default, it returns a hash containing the parent Fiber's variables (from `Thread.current[...]`). You can add to this hash in your own implementation of this method.
+- __[GraphQL::Dataloader#set_fiber_variables](rdoc-ref:GraphQL::Dataloader#set_fiber_variables)__ is called inside the new Fiber. It's passed the hash returned from `get_fiber_variables`. You can use this method to initialize "global" state inside the new Fiber.
+- __[GraphQL::Dataloader#cleanup_fiber](rdoc-ref:GraphQL::Dataloader#cleanup_fiber)__ is called just before a Dataloader Fiber exits. You can use this methods to teardown any state that you prepared in `set_fiber_variables`.
diff --git a/guides/dataloader/overview.md b/guides/dataloader/overview.md
index e842ae94220..bd2ee009b89 100644
--- a/guides/dataloader/overview.md
+++ b/guides/dataloader/overview.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Overview
-desc: Getting started with the Fiber-based Dataloader
-index: 0
----
+# Overview
- {{ "GraphQL::Dataloader" | api_doc }} provides efficient, batched access to external services, backed by Ruby's `Fiber` concurrency primitive. It has a per-query result cache and {% internal_link "AsyncDataloader", "/dataloader/async_dataloader" %} supports truly parallel execution out-of-the-box.
+ [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) provides efficient, batched access to external services, backed by Ruby's `Fiber` concurrency primitive. It has a per-query result cache and [AsyncDataloader](/dataloader/async_dataloader) supports truly parallel execution out-of-the-box.
`GraphQL::Dataloader` is inspired by [`@bessey`'s proof-of-concept](https://github.com/bessey/graphql-fiber-test/tree/no-gem-changes) and [shopify/graphql-batch](https://github.com/shopify/graphql-batch).
@@ -34,11 +27,11 @@ At a high level, `GraphQL::Dataloader`'s usage of `Fiber` looks like this:
Whenever `GraphQL::Dataloader` creates a new `Fiber`, it copies each pair from `Thread.current[...]` and reassigns them inside the new `Fiber`.
-`AsyncDataloader`, built on top of the [`async` gem](https://github.com/socketry/async), supports parallel I/O operations (like network and database communication) via Ruby's non-blocking `Fiber.schedule` API. {% internal_link "Learn more →", "/dataloader/async_dataloader" %}.
+`AsyncDataloader`, built on top of the [`async` gem](https://github.com/socketry/async), supports parallel I/O operations (like network and database communication) via Ruby's non-blocking `Fiber.schedule` API. [Learn more →](/dataloader/async_dataloader).
## Getting Started
-To install {{ "GraphQL::Dataloader" | api_doc }}, add it to your schema with `use ...`, for example:
+To install [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader), add it to your schema with `use ...`, for example:
```ruby
class MySchema < GraphQL::Schema
@@ -130,11 +123,11 @@ end
## Data Sources
-To implement batch-loading data sources, see the {% internal_link "Sources guide", "/dataloader/sources" %}.
+To implement batch-loading data sources, see the [Sources guide](/dataloader/sources).
## Parallelism
You can run I/O operations in parallel with GraphQL::Dataloader. There are two approaches:
-- `AsyncDataloader` uses the `async` gem to automatically background I/O from `Dataloader::Source#fetch` calls. {% internal_link "Read More", "/dataloader/async_dataloader" %}
-- You can manually call `dataloader.yield` after starting work in the background. {% internal_link "Read More", "/dataloader/parallelism" %}
+- `AsyncDataloader` uses the `async` gem to automatically background I/O from `Dataloader::Source#fetch` calls. [Read More](/dataloader/async_dataloader)
+- You can manually call `dataloader.yield` after starting work in the background. [Read More](/dataloader/parallelism)
diff --git a/guides/dataloader/parallelism.md b/guides/dataloader/parallelism.md
index a0634bb7bf4..a4fabf351ad 100644
--- a/guides/dataloader/parallelism.md
+++ b/guides/dataloader/parallelism.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Manual Parallelism
-desc: Yield to Dataloader after starting work
-index: 7
----
+# Manual Parallelism
-You can coordinate with {{ "GraphQL::Dataloader" | api_doc }} to run tasks in the background. To do this, call `dataloader.yield` inside `Source#fetch` after kicking off your task. For example:
+You can coordinate with [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) to run tasks in the background. To do this, call `dataloader.yield` inside `Source#fetch` after kicking off your task. For example:
```ruby
def fetch(ids)
@@ -23,7 +16,7 @@ def fetch(ids)
end
```
-_Alternatively, you can use {% internal_link "AsyncDataloader", "/dataloader/async_dataloader" %} to automatically background I/O inside `Source#fetch` calls._
+_Alternatively, you can use [AsyncDataloader](/dataloader/async_dataloader) to automatically background I/O inside `Source#fetch` calls._
## Example: Rails load_async
diff --git a/guides/dataloader/sources.md b/guides/dataloader/sources.md
index 0dc4b03ddb8..56520c670d3 100644
--- a/guides/dataloader/sources.md
+++ b/guides/dataloader/sources.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Sources
-desc: Batch-loading objects for GraphQL::Dataloader
-index: 1
----
+# Sources
-_Sources_ are what {{ "GraphQL::Dataloader" | api_doc }} uses to fetch data from external services.
+_Sources_ are what [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) uses to fetch data from external services.
## Source Concepts
@@ -27,7 +20,7 @@ Sources will receive two kinds of inputs from `GraphQL::Dataloader`:
(`dataloader.with(source_class, *batch_parameters)` returns an instance of `source_class` with the given batch parameters -- but it might be an instance which was cached by `dataloader`.)
- Additionally, batch parameters are used to de-duplicate Source initializations during a query run. `.with(...)` calls that have the same batch parameters will use the same Source instance under the hood. To customize how Sources are de-duplicated, see {{ "GraphQL::Dataloader::Source.batch_key_for" | api_doc }}.
+ Additionally, batch parameters are used to de-duplicate Source initializations during a query run. `.with(...)` calls that have the same batch parameters will use the same Source instance under the hood. To customize how Sources are de-duplicated, see [GraphQL::Dataloader::Source.batch_key_for](rdoc-ref:GraphQL::Dataloader::Source.batch_key_for).
## Example: Loading Strings from Redis by Key
@@ -132,11 +125,11 @@ def fetch(keys)
end
```
-See the {% internal_link "parallelism guide", "/dataloader/parallelism" %} for details about this approach.
+See the [parallelism guide](/dataloader/parallelism) for details about this approach.
## Filling the Dataloader Cache
-If you load records from the database, you can use them to populate a source's cache by using {{ "Dataloader::Source#merge" | api_doc }}. For example:
+If you load records from the database, you can use them to populate a source's cache by using [Dataloader::Source#merge](rdoc-ref:GraphQL::Dataloader::Source#merge). For example:
```ruby
# Build a `{ key => value }` map to populate the cache
diff --git a/guides/dataloader/testing.md b/guides/dataloader/testing.md
index 5742c6b897b..f339bc686d6 100644
--- a/guides/dataloader/testing.md
+++ b/guides/dataloader/testing.md
@@ -1,13 +1,6 @@
----
-layout: guide
-search: true
-section: Dataloader
-title: Testing
-desc: Tips for testing Dataloader implementation
-index: 4
----
+# Testing
-There are a few techniques for testing your {{ "GraphQL::Dataloader" | api_doc }} setup.
+There are a few techniques for testing your [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) setup.
## Integration Tests
@@ -43,7 +36,7 @@ You could also make specific assertions on the queries that are run (see the [`s
## Testing Dataloader Sources
-You can also test `Dataloader` behavior outside of GraphQL using {{ "GraphQL::Dataloader.with_dataloading" | api_doc }}. For example, let's say you have a `Sources::ActiveRecord` source defined like so:
+You can also test `Dataloader` behavior outside of GraphQL using [GraphQL::Dataloader.with_dataloading](rdoc-ref:GraphQL::Dataloader.with_dataloading). For example, let's say you have a `Sources::ActiveRecord` source defined like so:
```ruby
diff --git a/guides/defer/graphiql.md b/guides/defer/graphiql.md
index 661abeeabfa..b40e1db125e 100644
--- a/guides/defer/graphiql.md
+++ b/guides/defer/graphiql.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - Defer
-title: Use with GraphiQL
-desc: Using @defer with the GraphiQL IDE
-index: 4
-pro: true
----
+# Use with GraphiQL
You can use `@defer` and `@stream` with [GraphiQL](https://github.com/graphql/graphiql/blob/main/packages/graphiql/README.md), an in-browser IDE.
diff --git a/guides/defer/overview.md b/guides/defer/overview.md
index 0b58e7b915d..2fc9abe1db4 100644
--- a/guides/defer/overview.md
+++ b/guides/defer/overview.md
@@ -1,21 +1,12 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - Defer
-title: Overview
-desc: What is @defer, and why use it?
-index: 0
-pro: true
----
-
-`@defer` is a {% internal_link "directive", "/type_definitions/directives" %} for streaming GraphQL responses from the server to the client.
+# Overview
+
+`@defer` is a [directive](/type_definitions/directives) for streaming GraphQL responses from the server to the client.
By streaming the response, the server can send the most critical (or most available) data _first_, following up with secondary data shortly afterward.
`@defer` was first described by [Lee Byron at React Europe 2015](https://youtu.be/ViXL0YQnioU?t=768) and got experimental support in [Apollo in 2018](https://blog.apollographql.com/introducing-defer-in-apollo-server-f6797c4e9d6e).
-`@stream` is like `@defer`, but it returns list items one at a time. Find details in the {% internal_link "Stream guide", "/defer/stream" %}.
+`@stream` is like `@defer`, but it returns list items one at a time. Find details in the [Stream guide](/defer/stream).
## Example
@@ -25,7 +16,7 @@ In this example, the local server maintains an index of items ("decks"), but the
Without `@defer`, the whole query is blocked until the last field is done resolving:
-{{ "https://user-images.githubusercontent.com/2231765/53442028-4a122b00-39d6-11e9-8e33-b91791bf3b98.gif" | link_to_img:"Rails without defer" }}
+
But, we can add `@defer` to slow fields:
@@ -44,7 +35,7 @@ But, we can add `@defer` to slow fields:
Then, the response will stream to the client bit by bit, so the page can load progressively:
-{{ "https://user-images.githubusercontent.com/2231765/53442027-4a122b00-39d6-11e9-8d7b-feb7a4f7962a.gif" | link_to_img:"Rails with defer" }}
+
This way, clients get a snappy feel from the app even while data is still loading.
@@ -58,4 +49,4 @@ View the full demo at https://github.com/rmosolgo/graphql_defer_example.
## Next Steps
-{% internal_link "Set up your server", "/defer/setup" %} to support `@defer` or read about {% internal_link "client usage", "/defer/usage" %} of it.
+[Set up your server](/defer/setup) to support `@defer` or read about [client usage](/defer/usage) of it.
diff --git a/guides/defer/setup.md b/guides/defer/setup.md
index fc8895c3bf7..1c600e5004e 100644
--- a/guides/defer/setup.md
+++ b/guides/defer/setup.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - Defer
-title: Server Setup
-desc: Configuring the schema and server to use @defer
-index: 1
-pro: true
----
+# Server Setup
Before using `@defer` in queries, you have to:
@@ -45,7 +36,7 @@ end
This will:
-- Attach a {% internal_link "custom directive", "/type_definitions/directives" %} called `@defer`
+- Attach a [custom directive](/type_definitions/directives) called `@defer`
- Add instrumentation to queries to track deferred work and execute it later
## Sending streaming responses
@@ -58,7 +49,7 @@ Many web frameworks have support for streaming responses, for example:
See below for how to integrate GraphQL's deferred patches with a streaming response API.
-To investigate support with a web framework, please {% open_an_issue "Server support for @defer with ..." %} or email `support@graphql.pro`.
+To investigate support with a web framework, please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Server+support+for+%40defer+with+...&body=) or email `support@graphql.pro`.
### Checking for deferrals
@@ -166,4 +157,4 @@ use Directives::Defer
```
## Next Steps
-Read about {% internal_link "client usage", "/defer/usage" %} of `@defer`.
+Read about [client usage](/defer/usage) of `@defer`.
diff --git a/guides/defer/stream.md b/guides/defer/stream.md
index 6dd3d1ac150..6c3f5999696 100644
--- a/guides/defer/stream.md
+++ b/guides/defer/stream.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - Defer
-title: Stream
-desc: Using @stream to receive list items one at a time
-index: 3
-pro: true
----
+# Stream
`@stream` works very much like `@defer`, except it only applies to list fields. When a field has `@stream` and it returns a list, then each item in the list is returned to the client as a patch. `@stream` is described in a [proposal to the GraphQL specification](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md).
@@ -24,7 +15,7 @@ class MySchema < GraphQL::Schema
end
```
-Additionally, you should update your controller to handle deferred parts of the response. See the {% internal_link "@defer setup guide", "defer/setup#sending-streaming-responses" %} for details. (`@stream` uses the same deferral pipeline as `@defer`, so the same setup instructions apply.)
+Additionally, you should update your controller to handle deferred parts of the response. See the [@defer setup guide](/defer/setup#sending-streaming-responses) for details. (`@stream` uses the same deferral pipeline as `@defer`, so the same setup instructions apply.)
## Usage
diff --git a/guides/defer/usage.md b/guides/defer/usage.md
index 92925da3fec..46a9da50890 100644
--- a/guides/defer/usage.md
+++ b/guides/defer/usage.md
@@ -1,14 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - Defer
-title: Usage
-desc: Using @defer on the client side
-index: 2
-pro: true
----
-
+# Usage
`@defer` is a [GraphQL directive](https://graphql.org/learn/queries/#directives) which instructs the server to execute the field in a special way:
@@ -28,8 +18,8 @@ Apollo-Client [currently supports the @defer directive](https://www.apollographq
`@defer` also accepts a `label:` option which will be included in outgoing patches when it's present in the query (eg, `@defer(label: "patch1")`).
-Want to use `@defer` with another client? Please {% open_an_issue "Client support for @defer with ..." %} or email `support@graphql.pro` and we'll dig in!
+Want to use `@defer` with another client? Please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Client+support+for+%40defer+with+...&body=) or email `support@graphql.pro` and we'll dig in!
## Next Steps
-{% internal_link "Set up your server", "/defer/setup" %} to support `@defer`.
+[Set up your server](/defer/setup) to support `@defer`.
diff --git a/guides/development.md b/guides/development.md
index 935ab067800..b0d572460fb 100644
--- a/guides/development.md
+++ b/guides/development.md
@@ -1,23 +1,16 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Development
-section: Other
-desc: Hacking on GraphQL Ruby
----
+# Development
So, you want to hack on GraphQL Ruby! Here are some tips for getting started.
-- [Setup](#setup) your development environment
-- [Run the tests](#running-the-tests) to verify your setup
-- [Debug](#debugging-with-pry) with pry
-- [Run the benchmarks](#running-the-benchmarks) to test performance in your environment
-- [Coding guidelines](#coding-guidelines) for working on your contribution
+- [Setup your development environment](#setup)
+- [Run the tests to verify your setup](#running-the-tests)
+- [Debug with pry](#debugging-with-pry)
+- [Run the benchmarks to test performance in your environment](#running-the-benchmarks)
+- [Coding guidelines for working on your contribution](#coding-guidelines)
- Special tools for building the lexer and parser
-- Building and publishing the [GraphQL Ruby website](#website)
-- [Versioning](#versioning) describes how changes are managed and released
-- [Releasing](#releasing) Gem versions
+- [Building and publishing the GraphQL Ruby website](#website)
+- [Versioning describes how changes are managed and released](#versioning)
+- [Releasing Gem versions](#releasing)
## Setup
@@ -167,54 +160,32 @@ Don't fret about coding style or organization. There's a minimal Rubocop config
To update the website, update the `.md` files in `guides/`.
-To preview your changes, you can serve the website locally:
+Install the optional documentation dependencies and build the site locally:
+```sh
+BUNDLE_WITH=docs bundle install
+bundle exec rake docs:build
+bundle exec rake docs:rdoc:serve
```
-bundle exec rake site:serve
-```
-
-Then visit `http://localhost:4000`.
-
-To publish the website with GitHub pages, run the Rake task:
-
-```
-bundle exec rake site:publish
-```
-
-### Search Index
-GraphQL-Ruby's search index is powered by Algolia. To update the index, you need the API key in an environment variable:
+Then visit `http://127.0.0.1:8808`. Run the documentation checks before submitting a change:
-```
-$ export ALGOLIA_API_KEY=...
+```sh
+bundle exec rake docs:check
+bundle exec rake docs:build_twice
```
-Without this key, the search index will fall out-of-sync with the website. Contact @rmosolgo to gain access to this key.
+See the [documentation maintenance guide](/docs/maintenance) for API links, GraphQL code blocks, redirects, and release documentation.
### API Docs
-The GraphQL-Ruby website has its own rendered version of the gem's API docs. They're pushed to GitHub pages with a special process.
-
-First, generate local copies of the docs you want to publish:
-
-```
-$ bundle exec rake apidocs:gen_version[1.8.0] # for example, generate docs that you want to publish
-```
-
-Then, check them out locally:
-
-```
-$ bundle exec rake site:serve
-# then visit http://localhost:4000/api-doc/1.8.0/
-```
-
-Then, publish them as part of the whole site:
+The GraphQL-Ruby website has a rendered version of each published gem's API docs. Generate a local copy with:
```
-$ bundle exec rake site:publish
+$ bundle exec rake "docs:rdoc:build_version[1.8.0]"
```
-Finally, check your work by visiting the docs on the website.
+The output is written to `tmp/rdoc-api/1.8.0/`; the release workflow publishes it under `/api-doc/1.8.0/` while preserving older versions.
## Versioning
diff --git a/guides/errors/error_handling.md b/guides/errors/error_handling.md
index 0b49bb31221..ce254f36f87 100644
--- a/guides/errors/error_handling.md
+++ b/guides/errors/error_handling.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Errors
-title: Error Handling
-desc: Rescuing application errors from field resolvers
-index: 3
----
+# Error Handling
You can configure your schema to rescue application errors during field resolution. Errors during batch loading will also be rescued.
@@ -40,11 +32,11 @@ The handler is called with several arguments:
- __`obj`__ is the object which was having a field resolved against it
- __`args`__ is the Hash of arguments passed to the resolver
- __`ctx`__ is the query context
-- __`field`__ is the {{ "GraphQL::Schema::Field" | api_doc }} instance for the field where the error was rescued
+- __`field`__ is the [GraphQL::Schema::Field](rdoc-ref:GraphQL::Schema::Field) instance for the field where the error was rescued
Inside the handler, you can:
-- Raise a GraphQL-friendly {{ "GraphQL::ExecutionError" | api_doc }} to return to the user
+- Raise a GraphQL-friendly [GraphQL::ExecutionError](rdoc-ref:GraphQL::ExecutionError) to return to the user
- Re-raise the given `err` to crash the query and halt execution. (The error will propagate to your application, eg, the controller.)
- Report some metrics from the error, if applicable
- Return a new value to be used for the error case (if not raising another error)
diff --git a/guides/errors/execution_errors.md b/guides/errors/execution_errors.md
index 8f5cc0c974c..75943454d04 100644
--- a/guides/errors/execution_errors.md
+++ b/guides/errors/execution_errors.md
@@ -1,13 +1,3 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Errors
-title: Top-level "errors"
-desc: The top-level "errors" array and how to use it.
-index: 1
----
-
The GraphQL specification [allows for a top-level `"errors"` key](https://graphql.github.io/graphql-spec/June2018/#sec-Errors) in the response which may contain information about what went wrong during execution. For example:
```ruby
@@ -31,7 +21,7 @@ In general, top-level errors should only be used for exceptional circumstances w
For example, the GraphQL specification says that when a non-null field returns `nil`, an error should be added to the `"errors"` key. This kind of error is not recoverable by the client. Instead, something on the server should be fixed to handle this case.
-When you want to notify a client some kind of recoverable issue, consider making error messages part of the schema, for example, as in {% internal_link "mutation errors", "/mutations/mutation_errors" %}.
+When you want to notify a client some kind of recoverable issue, consider making error messages part of the schema, for example, as in [mutation errors](/mutations/mutation_errors).
## Adding Errors to the Array
diff --git a/guides/errors/overview.md b/guides/errors/overview.md
index c15fbc93f19..3e94ec20ef9 100644
--- a/guides/errors/overview.md
+++ b/guides/errors/overview.md
@@ -1,15 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Errors
-title: Errors in GraphQL
-desc: A conceptual introduction to errors in GraphQL
-index: 0
-redirect_from:
- - /schema/type_errors/
- - /queries/error_handling/
----
+# Errors in GraphQL
There are a _lot_ of different kinds of errors in GraphQL! In this guide, we'll discuss some of the main categories and learn when they apply.
@@ -27,11 +16,11 @@ Each error has a message, line, column and path.
The validation rules are part of the GraphQL specification and built into GraphQL-Ruby, so there's not really a way to customize this behavior, except to pass `validate: false` when executing a query, which skips validation altogether.
-You can configure your schema to stop validating after a certain number of errors by setting {{ "Schema.validate_max_errors" | api_doc }}. Also, you can add a timeout to this step with {{ "Schema.validate_timeout" | api_doc }}.
+You can configure your schema to stop validating after a certain number of errors by setting [Schema.validate_max_errors](rdoc-ref:GraphQL::Schema.validate_max_errors). Also, you can add a timeout to this step with [Schema.validate_timeout](rdoc-ref:GraphQL::Schema.validate_timeout).
## Analysis Errors
-GraphQL-Ruby supports pre-execution analysis, which may return `"errors"` instead of running a query. You can find details in the {% internal_link "Analysis guide", "queries/ast_analysis" %}.
+GraphQL-Ruby supports pre-execution analysis, which may return `"errors"` instead of running a query. You can find details in the [Analysis guide](/queries/ast_analysis).
## GraphQL Invariants
@@ -40,17 +29,17 @@ While GraphQL-Ruby is executing a query, some constraints must be satisfied. For
- Non-null fields may not return `nil`.
- Interface and union types must resolve objects to types that belong to that interface/union.
-These constraints are part of the GraphQL specification, and when they are violated, it must be addressed somehow. Read more in {% internal_link "Type Errors", "/errors/type_errors" %}.
+These constraints are part of the GraphQL specification, and when they are violated, it must be addressed somehow. Read more in [Type Errors](/errors/type_errors).
## Top-level `"errors"`
The GraphQL specification provides for a top-level `"errors"` key which may include information about errors during query execution. `"errors"` and `"data"` may _both_ be present in the case of a partial success.
-In your own schema, you can add to the `"errors"` key by raising `GraphQL::ExecutionError` (or subclasses of it) in your code. Read more in the {% internal_link "Execution Errors guide", "/errors/execution_errors" %}.
+In your own schema, you can add to the `"errors"` key by raising `GraphQL::ExecutionError` (or subclasses of it) in your code. Read more in the [Execution Errors guide](/errors/execution_errors).
## Handled Errors
-A schema can be configured to handle certain errors during field execution with handlers that you give it, using `rescue_from`. Read more in the {% internal_link "Error Handling guide", "/errors/error_handling" %}.
+A schema can be configured to handle certain errors during field execution with handlers that you give it, using `rescue_from`. Read more in the [Error Handling guide](/errors/error_handling).
## Unhandled Errors (Crashes)
@@ -62,4 +51,4 @@ For example, Rails will probably return a generic `500` page.
When you want end users (human beings) to read error messages, you can express errors _in the schema_, using normal GraphQL fields and types. In this approach, errors are strongly-typed data, queryable in the schema, like any other application data.
-For more about this approach, see {% internal_link "Mutation Errors", "/mutations/mutation_errors.html#errors-as-data" %}
+For more about this approach, see [Mutation Errors](/mutations/mutation_errors.html#errors-as-data)
diff --git a/guides/errors/type_errors.md b/guides/errors/type_errors.md
index 0edc12c62b3..4eb64ddd5fa 100644
--- a/guides/errors/type_errors.md
+++ b/guides/errors/type_errors.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Errors
-title: Type Errors
-desc: Handling type errors
-index: 3
----
+# Type Errors
The GraphQL specification _requires_ certain assumptions to hold true when executing a query. However, it's possible that some code would violate that assumption, resulting in a type error.
@@ -15,7 +7,7 @@ Here are two type errors that you can customize in GraphQL-Ruby:
- A field with `null: false` returned `nil`
- A field returned a value as a union or interface, but that value couldn't be resolved to a member of that union or interface.
-You can specify behavior in these cases by defining a {{ "Schema.type_error" | api_doc }} hook:
+You can specify behavior in these cases by defining a [Schema.type_error](rdoc-ref:GraphQL::Schema.type_error) hook:
```ruby
class MySchema < GraphQL::Schema
@@ -25,11 +17,11 @@ class MySchema < GraphQL::Schema
end
```
-It is called with an instance of {{ "GraphQL::UnresolvedTypeError" | api_doc }} or {{ "GraphQL::InvalidNullError" | api_doc }} and the query context (a {{ "GraphQL::Query::Context" | api_doc }}).
+It is called with an instance of [GraphQL::UnresolvedTypeError](rdoc-ref:GraphQL::UnresolvedTypeError) or [GraphQL::InvalidNullError](rdoc-ref:GraphQL::InvalidNullError) and the query context (a [GraphQL::Query::Context](rdoc-ref:GraphQL::Query::Context)).
If you don't specify a hook, you get the default behavior:
- Unexpected `nil`s add an error the response's `"errors"` key
-- Unresolved Union / Interface types raise {{ "GraphQL::UnresolvedTypeError" | api_doc }}
+- Unresolved Union / Interface types raise [GraphQL::UnresolvedTypeError](rdoc-ref:GraphQL::UnresolvedTypeError)
An object that fails type resolution is treated as `nil`.
diff --git a/guides/execution/migration.md b/guides/execution/migration.md
index 3c7dea561d5..f129bf1098f 100644
--- a/guides/execution/migration.md
+++ b/guides/execution/migration.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Execution
-title: Migrating to Execution::Next
-desc: Guidelines for migrating to the new execution engine
-index: 2
----
+# Migrating to Execution::Next
This guide includes tips for migrating your schema configuration and production traffic to the new engine.
@@ -14,7 +6,7 @@ This guide includes tips for migrating your schema configuration and production
`Execution::Next` is designed to run alongside the previous engine so that the same schema can run queries _both_ ways. This supports an incremental migration and live toggling in production.
-First, update your schema to include the necessary {% internal_link "field configurations", "/execution/next#field-configurations" %}. If you implement new class methods in your Object type classes, you can also migrate instance methods to call "up" to those class methods, preserving a single source of truth:
+First, update your schema to include the necessary [field configurations](/execution/next#field-configurations). If you implement new class methods in your Object type classes, you can also migrate instance methods to call "up" to those class methods, preserving a single source of truth:
```ruby
field :unpublished_posts, [Types::Post], resolve_each: true
@@ -207,7 +199,7 @@ Visibility works exactly as before; both runtime modules call the same methods t
### Dataloader
-Dataloader runs with new execution, but when migrating from instance methods to batch-level class methods, you may need to use {{ "Schema::Member::HasDataloader#dataload_all" | api_doc }} instead of `.dataload`.
+Dataloader runs with new execution, but when migrating from instance methods to batch-level class methods, you may need to use [Schema::Member::HasDataloader#dataload_all](rdoc-ref:GraphQL::Schema::Member::HasDataloader#dataload_all) instead of `.dataload`.
### Tracing
diff --git a/guides/execution/next.md b/guides/execution/next.md
index 28dcc86fd0c..0e60005eee8 100644
--- a/guides/execution/next.md
+++ b/guides/execution/next.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Execution
-title: New Execution Module
-desc: Background on GraphQL-Ruby's new execution approach
-index: 1
----
-
-GraphQL-Ruby has a new execution engine, {{ "GraphQL::Execution::Next" | api_doc }}. It's much faster and less memory-consuming than the existing execution engine, but requires some care in migrating.
+# New Execution Module
+
+GraphQL-Ruby has a new execution engine, [GraphQL::Execution::Next](rdoc-ref:GraphQL::Execution::Next). It's much faster and less memory-consuming than the existing execution engine, but requires some care in migrating.
This feature is in heavy development, so if you give it a try and run into any problems, please open an issue on GitHub!
@@ -37,7 +29,7 @@ The new execution engine is enabled with two steps:
- Add the plugin to your schema with `use GraphQL::Execution::Next`
- Call `MySchema.execute_next(...)` instead of `MySchema.execute(...)`. It takes the same arguments.
-See {% internal_link "compatibility notes", "/execution/migration#compatibility-notes" %} for updating your schema to run queries with the new engine.
+See [compatibility notes](/execution/migration#compatibility-notes) for updating your schema to run queries with the new engine.
You can also add `..., as_default: true` to use `execute_next` by default. In that case, call `execute_legacy` if you need the old runtime.
@@ -188,7 +180,7 @@ class Types::CommentType
#### Rails Associations
-Load ActiveRecord associations using {{ "GraphQL::Dataloader::ActiveRecordAssociationSource" | api_doc }}:
+Load ActiveRecord associations using [GraphQL::Dataloader::ActiveRecordAssociationSource](rdoc-ref:GraphQL::Dataloader::ActiveRecordAssociationSource):
```ruby
class Types::CommentType < Types::BaseObject
@@ -201,7 +193,7 @@ end
#### Rails Records
-Load ActiveRecord associations using {{ "GraphQL::Dataloader::ActiveRecordSource" | api_doc }}.
+Load ActiveRecord associations using [GraphQL::Dataloader::ActiveRecordSource](rdoc-ref:GraphQL::Dataloader::ActiveRecordSource).
```ruby
class Types::SearchResult < Types::BaseObject
@@ -248,4 +240,4 @@ end
## Migration
-Read about migrating in the {% internal_link "Migration Doc", "/execution/migration" %}.
+Read about migrating in the [Migration Doc](/execution/migration).
diff --git a/guides/faq.md b/guides/faq.md
index eab9a195531..98baee2ab45 100644
--- a/guides/faq.md
+++ b/guides/faq.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: FAQ
-other: true
-desc: How to do common tasks
----
-
+# FAQ
Returning Route URLs
====================
diff --git a/guides/fields/arguments.md b/guides/fields/arguments.md
index a6f38a7c191..8e2e0f646ae 100644
--- a/guides/fields/arguments.md
+++ b/guides/fields/arguments.md
@@ -1,176 +1,13 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Fields
-title: Arguments
-desc: Fields may take arguments as inputs
-index: 1
----
+# Arguments
-Fields can take **arguments** as input. These can be used to determine the return value (eg, filtering search results) or to modify the application state (eg, updating the database in `MutationType`).
+Arguments are part of the GraphQL::Schema::Argument API. The complete
+reference, including nullability, defaults, deprecation, aliasing,
+preprocessing, camelization, and supported input types, is maintained with
+the implementation:
-Arguments are defined with the `argument` helper. These arguments are passed as [keyword arguments](https://robots.thoughtbot.com/ruby-2-keyword-arguments) to the resolver method:
+[GraphQL::Schema::Argument](rdoc-ref:GraphQL::Schema::Argument)
-```ruby
-field :search_posts, [PostType], null: false do
- argument :category, String
-end
-
-def search_posts(category:)
- Post.where(category: category).limit(10)
-end
-```
-
-## Nullability
-
-To make an argument optional, set `required: false`, and set default values for the corresponding keyword arguments:
-
-```ruby
-field :search_posts, [PostType], null: false do
- argument :category, String, required: false
-end
-
-def search_posts(category: nil)
- if category
- Post.where(category: category).limit(10)
- else
- Post.all.limit(10)
- end
-end
-```
-
-Be aware that if all arguments are optional and the query does not provide any arguments, then the resolver method will be called with no arguments. To prevent an `ArgumentError` in this case, you must either specify default values for all keyword arguments (as done in the prior example) or use the double splat operator argument in the method definition. For example:
-
-```ruby
-def search_posts(**args)
- if args[:category]
- Post.where(category: args[:category]).limit(10)
- else
- Post.all.limit(10)
- end
-end
-```
-
-### Default Values
-
-Another approach is to use `default_value: value` to provide a default value for the argument if it is not supplied in the query.
-
-```ruby
-field :search_posts, [PostType], null: false do
- argument :category, String, required: false, default_value: "Programming"
-end
-
-def search_posts(category:)
- Post.where(category: category).limit(10)
-end
-```
-
-Arguments with `required: false` _do_ accept `null` as inputs from clients. This can be surprising in resolver code, for example, an argument with `Integer, required: false` can sometimes be `nil`. In this case, you can use `replace_null_with_default: true` to apply the given `default_value: ...` when clients provide `null`. For example:
-
-```ruby
-# Even if clients send `query: null`, the resolver will receive `"*"` for this argument:
-argument :query, String, required: false, default_value: "*", replace_null_with_default: true
-```
-
-Finally, `required: :nullable` will require clients to pass the argument, although it will accept `null` as a valid input. For example:
-
-```ruby
-# This argument _must_ be given -- send `null` if there's no other appropriate value:
-argument :email_address, String, required: :nullable
-```
-
-
-## Deprecation
-
-**Experimental:** __Deprecated__ arguments can be marked by adding a `deprecation_reason:` keyword argument:
-
-```ruby
-field :search_posts, [PostType], null: false do
- argument :name, String, required: false, deprecation_reason: "Use `query` instead."
- argument :query, String, required: false
-end
-```
-
-## Aliasing
-
-Use `as: :alternate_name` to use a different key from within your resolvers while
-exposing another key to clients.
-
-```ruby
-field :post, PostType, null: false do
- argument :post_id, ID, as: :id
-end
-
-def post(id:)
- Post.find(id)
-end
-```
-
-## Preprocessing
-
-Provide a `prepare` function to modify or validate the value of an argument before the field's resolver method is executed:
-
-```ruby
-field :posts, [PostType], null: false do
- argument :start_date, String, prepare: ->(startDate, ctx) {
- # return the prepared argument.
- # raise a GraphQL::ExecutionError to halt the execution of the field and
- # add the exception's message to the `errors` key.
- }
-end
-
-def posts(start_date:)
- # use prepared start_date
-end
-```
-
-## Automatic camelization
-
-Arguments that are snake_cased will be camelized in the GraphQL schema. Using the example of:
-
-```ruby
-field :posts, [PostType], null: false do
- argument :start_year, Int
-end
-```
-
-The corresponding GraphQL query will look like:
-
-```graphql
-{
- posts(startYear: 2018) {
- id
- }
-}
-```
-
-To disable auto-camelization, pass `camelize: false` to the `argument` method.
-
-```ruby
-field :posts, [PostType], null: false do
- argument :start_year, Int, camelize: false
-end
-```
-
-Furthermore, if your argument is already camelCased, then it will remain camelized in the GraphQL schema. However, the argument will be converted to snake_case when it is passed to the resolver method:
-
-```ruby
-field :posts, [PostType], null: false do
- argument :startYear, Int
-end
-
-def posts(start_year:)
- # ...
-end
-```
-
-## Valid Argument Types
-
-Only certain types are valid for arguments:
-
-- {{ "GraphQL::Schema::Scalar" | api_doc }}, including built-in scalars (string, int, float, boolean, ID)
-- {{ "GraphQL::Schema::Enum" | api_doc }}
-- {{ "GraphQL::Schema::InputObject" | api_doc }}, which allows key-value pairs as input
-- {{ "GraphQL::Schema::List" | api_doc }}s of a valid input type, configured using `[...]`
-- {{ "GraphQL::Schema::NonNull" | api_doc }}s of a valid input type (arguments are non-null by default; use `required: false` to make optional arguments)
+Use that API reference for the exact argument(...) parameters and runtime
+behavior. This guide remains the entry point for field arguments and connects
+the topic to the [fields](/fields/introduction) and
+[validation](/fields/validation) guides.
diff --git a/guides/fields/introduction.md b/guides/fields/introduction.md
index c84fd8d3d9e..0ab2d252a3f 100644
--- a/guides/fields/introduction.md
+++ b/guides/fields/introduction.md
@@ -1,275 +1,41 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Fields
-title: Introduction
-desc: Implement fields and resolvers with the Ruby DSL
-index: 0
----
+# Field definitions
+Field definitions are part of the GraphQL::Schema::Field API. The complete
+reference, including names, return types, descriptions, resolution behavior,
+arguments, extras, and default options, is maintained with the implementation:
-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:
+[GraphQL::Schema::Field](rdoc-ref:GraphQL::Schema::Field)
-```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, comments 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)
+Use that API reference when you need the exact field(...) parameters and
+runtime behavior. This guide remains the entry point for the fields section
+and links to the related [objects](/type_definitions/objects),
+[interfaces](/type_definitions/interfaces), and
+[arguments](/fields/arguments) guides.
## 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).
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## 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
-```
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## Field Documentation
-Fields may be documented with a __description__, __comment__ 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
-```
-
-__Comments__ can be added with the `field(...)` method as a keyword argument, or inside the block:
-```ruby
-# `comment:` keyword
-field :name, String, null: false, comment: "Rename to full name"
-
-# inside the block
-field :name, String, null: false do
- comment "Rename to full name"
-end
-```
-
-Generates field name with comment above "Rename to full name" above.
-
-```graphql
-type Foo {
- # Rename to full name
- name: String!
-}
-```
-
-__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.
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## 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`.
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## 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" %}
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## 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` (Interpreter 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.
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
## 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.
+See the [Field API reference](rdoc-ref:GraphQL::Schema::Field).
diff --git a/guides/fields/limits.md b/guides/fields/limits.md
index 0f03eb9bd86..cae85440e78 100644
--- a/guides/fields/limits.md
+++ b/guides/fields/limits.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Fields
-title: Limits
-desc: Always limit lists of items
-index: 4
----
+# Limits
## List Fields
@@ -27,4 +19,4 @@ This way, you won't hit your database for 1000 items!
## Connections
-Connections accept a {% internal_link "`max_page_size` option","/pagination/using_connections#max-page-size" %} which limits the number of nodes.
+Connections accept a [`max_page_size` option](/pagination/using_connections#max-page-size) which limits the number of nodes.
diff --git a/guides/fields/resolvers.md b/guides/fields/resolvers.md
index 4ba1320b984..2da15a09a31 100644
--- a/guides/fields/resolvers.md
+++ b/guides/fields/resolvers.md
@@ -1,23 +1,13 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Fields
-title: Resolvers
-desc: Reusable, extendable resolution logic for complex fields
-index: 2
-redirect_from:
- - /fields/functions
----
-
-A {{ "GraphQL::Schema::Resolver" | api_doc }} is a container for field signature and resolution logic. It can be attached to a field with the `resolver:` keyword:
+# Resolvers
+
+A [GraphQL::Schema::Resolver](rdoc-ref:GraphQL::Schema::Resolver) is a container for field signature and resolution logic. It can be attached to a field with the `resolver:` keyword:
```ruby
# Use the resolver class to execute this field
field :pending_orders, resolver: PendingOrders
```
-Under the hood, {{ "GraphQL::Schema::Mutation" | api_doc }} is a specialized subclass of `Resolver`.
+Under the hood, [GraphQL::Schema::Mutation](rdoc-ref:GraphQL::Schema::Mutation) is a specialized subclass of `Resolver`.
## First, ask yourself ...
@@ -88,7 +78,7 @@ class Types::User < BaseObject
end
```
-- If the module approach looks good to you, also consider {% internal_link "Interfaces", "/type_definitions/interfaces" %}. They also share behavior between objects (since they're just modules that get included, after all), and they expose that commonality to clients via introspection.
+- If the module approach looks good to you, also consider [Interfaces](/type_definitions/interfaces). They also share behavior between objects (since they're just modules that get included, after all), and they expose that commonality to clients via introspection.
## When do you really need a resolver?
diff --git a/guides/fields/validation.md b/guides/fields/validation.md
index 3eb860c661e..7f0d06a027f 100644
--- a/guides/fields/validation.md
+++ b/guides/fields/validation.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Fields
-title: Validation
-desc: Rails-like validations for arguments
-index: 3
----
+# Validation
Arguments can be validated at runtime using built-in or custom validators.
@@ -36,15 +28,15 @@ Validations can be provided with a keyword (`validates: { ... }`) or with a meth
See each validator's API docs for details:
-- `length: { maximum: ..., minimum: ..., is: ..., within: ... }` {{ "Schema::Validator::LengthValidator" | api_doc }}
-- `format: { with: /.../, without: /.../ }` {{ "Schema::Validator::FormatValidator" | api_doc }}
-- `numericality: { greater_than:, greater_than_or_equal_to:, less_than:, less_than_or_equal_to:, other_than:, odd:, even: }` {{ "Schema::Validator::NumericalityValidator" | api_doc }}
-- `inclusion: { in: [...] }` {{ "Schema::Validator::InclusionValidator" | api_doc }}
-- `exclusion: { in: [...] }` {{ "Schema::Validator::ExclusionValidator" | api_doc }}
-- `required: { one_of: [...] }` {{ "Schema::Validator::RequiredValidator" | api_doc }}
-- `allow_blank: true|false` {{ "Schema::Validator::AllowBlankValidator" | api_doc }}
-- `allow_null: true|false` {{ "Schema::Validator::AllowNullValidator" | api_doc }}
-- `all: { ... }` {{ "Schema::Validator::AllValidator" | api_doc }}
+- `length: { maximum: ..., minimum: ..., is: ..., within: ... }` [Schema::Validator::LengthValidator](rdoc-ref:GraphQL::Schema::Validator::LengthValidator)
+- `format: { with: /.../, without: /.../ }` [Schema::Validator::FormatValidator](rdoc-ref:GraphQL::Schema::Validator::FormatValidator)
+- `numericality: { greater_than:, greater_than_or_equal_to:, less_than:, less_than_or_equal_to:, other_than:, odd:, even: }` [Schema::Validator::NumericalityValidator](rdoc-ref:GraphQL::Schema::Validator::NumericalityValidator)
+- `inclusion: { in: [...] }` [Schema::Validator::InclusionValidator](rdoc-ref:GraphQL::Schema::Validator::InclusionValidator)
+- `exclusion: { in: [...] }` [Schema::Validator::ExclusionValidator](rdoc-ref:GraphQL::Schema::Validator::ExclusionValidator)
+- `required: { one_of: [...] }` [Schema::Validator::RequiredValidator](rdoc-ref:GraphQL::Schema::Validator::RequiredValidator)
+- `allow_blank: true|false` [Schema::Validator::AllowBlankValidator](rdoc-ref:GraphQL::Schema::Validator::AllowBlankValidator)
+- `allow_null: true|false` [Schema::Validator::AllowNullValidator](rdoc-ref:GraphQL::Schema::Validator::AllowNullValidator)
+- `all: { ... }` [Schema::Validator::AllValidator](rdoc-ref:GraphQL::Schema::Validator::AllValidator)
Some of the validators accept customizable messages for certain validation failures; see the API docs for examples.
diff --git a/guides/getting_started.md b/guides/getting_started.md
index 99ce10049bd..edc22d1bd1b 100644
--- a/guides/getting_started.md
+++ b/guides/getting_started.md
@@ -1,11 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Getting Started
-section: Other
-desc: Start here!
----
+# Getting Started
## Installation
@@ -106,7 +99,7 @@ class Schema < GraphQL::Schema
end
```
-This schema is ready to serve GraphQL queries! {% internal_link "Browse the guides","/guides" %} to learn about other GraphQL Ruby features.
+This schema is ready to serve GraphQL queries! [Browse the guides](/guides) to learn about other GraphQL Ruby features.
### Execute queries
@@ -133,14 +126,14 @@ result_hash = Schema.execute(query_string)
# }
```
-See {% internal_link "Executing Queries","/queries/executing_queries" %} for more information about running queries on your schema.
+See [Executing Queries](/queries/executing_queries) for more information about running queries on your schema.
## Use with Relay
If you're building a backend for [Relay](https://facebook.github.io/relay/), you'll need:
- A JSON dump of the schema, which you can get by sending [`GraphQL::Introspection::INTROSPECTION_QUERY`](https://github.com/rmosolgo/graphql-ruby/blob/master/lib/graphql/introspection/introspection_query.rb)
-- Relay-specific helpers for GraphQL, see the {% internal_link "Connection guide", "/pagination/connection_concepts" %}, {% internal_link "Mutation guide", "mutations/mutation_classes" %}, and {% internal_link "Object Identification guide", "/schema/object_identification" %}.
+- Relay-specific helpers for GraphQL, see the [Connection guide](/pagination/connection_concepts), [Mutation guide](/mutations/mutation_classes), and [Object Identification guide](/schema/object_identification).
## Use with Apollo Client
diff --git a/guides/guides.html b/guides/guides.html
deleted file mode 100644
index f221039a739..00000000000
--- a/guides/guides.html
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: Guides Index
-sections:
- - name: Schema
- - name: Queries
- - name: Execution
- - name: Type Definitions
- - name: Authorization
- - name: Fields
- - name: Mutations
- - name: Errors
- - name: Pagination
- - name: Relay
- - name: Dataloader
- - name: Subscriptions
- - name: GraphQL Pro
- - name: GraphQL Pro - OperationStore
- - name: GraphQL Pro - Defer
- - name: GraphQL Enterprise - Rate Limiters
- - name: GraphQL Enterprise - Object Cache
- - name: GraphQL Enterprise - Changesets
- - name: JavaScript Client
- - name: Language Tools
- - name: Testing
- - name: Other
----
-
-
- Provide custom data to clients and extend your API with
- {% internal_link "mutations", "/mutations/mutation_root" %},
- {% internal_link "subscriptions", "/subscriptions/overview" %},
- {% internal_link "streaming responses", "/defer/overview" %},
- and {% internal_link "multiplexing", "/queries/multiplex" %}.
-
diff --git a/guides/javascript_client/apollo_subscriptions.md b/guides/javascript_client/apollo_subscriptions.md
index 3b09d6f7b70..c9011e3d2ce 100644
--- a/guides/javascript_client/apollo_subscriptions.md
+++ b/guides/javascript_client/apollo_subscriptions.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: Apollo Subscriptions
-desc: GraphQL subscriptions with GraphQL-Ruby and Apollo Client
-index: 2
----
+# Apollo Subscriptions
GraphQL-Ruby's JavaScript client includes several kinds of support for Apollo Client:
@@ -63,7 +55,7 @@ const client = new ApolloClient({
This link will check responses for the `X-Subscription-ID` header, and if it's present, it will use that value to subscribe to Pusher for future updates.
-If you're using {% internal_link "compressed payloads", "/subscriptions/pusher_implementation#payload-compression" %}, configure a `decompress:` function, too:
+If you're using [compressed payloads](/subscriptions/pusher_implementation#payload-compression), configure a `decompress:` function, too:
```javascript
// Add `pako` to the project for gunzipping
@@ -124,7 +116,7 @@ This link will check responses for the `X-Subscription-ID` header, and if it's p
For your __app key__, make a key with "Subscribe" and "Presence" privileges and use that:
-{{ "/javascript_client/ably_key.png" | link_to_img:"Ably Subscription Key Privileges" }}
+
## Apollo Link -- ActionCable
@@ -171,11 +163,11 @@ Note that for Rails 5, the ActionCable client package is `actioncable`, not `@ra
## Apollo 1
-`graphql-ruby-client` includes support for Apollo 1 client subscriptions over {% internal_link "Pusher", "/subscriptions/pusher_implementation" %} or {% internal_link "ActionCable", "/subscriptions/action_cable_implementation" %}.
+`graphql-ruby-client` includes support for Apollo 1 client subscriptions over [Pusher](/subscriptions/pusher_implementation) or [ActionCable](/subscriptions/action_cable_implementation).
To use it, require `subscriptions/addGraphQLSubscriptions` and call the function with your network interface and transport client (example below).
-See the {% internal_link "Subscriptions guide", "/subscriptions/overview" %} for information about server-side setup.
+See the [Subscriptions guide](/subscriptions/overview) for information about server-side setup.
### Apollo 1 -- Pusher
@@ -195,7 +187,7 @@ var OperationStoreClient = require("./OperationStoreClient")
RailsNetworkInterface.use([OperationStoreClient.apolloMiddleware])
```
-If you're using {% internal_link "compressed payloads", "/subscriptions/pusher_implementation#payload-compression" %}, configure a `decompress:` function, too:
+If you're using [compressed payloads](/subscriptions/pusher_implementation#payload-compression), configure a `decompress:` function, too:
```javascript
// Add `pako` to the project for gunzipping
diff --git a/guides/javascript_client/graphiql_subscriptions.md b/guides/javascript_client/graphiql_subscriptions.md
index 6b1279d61e5..1ab6515e870 100644
--- a/guides/javascript_client/graphiql_subscriptions.md
+++ b/guides/javascript_client/graphiql_subscriptions.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: GraphiQL Subscriptions
-desc: Testing GraphQL subscriptions in the GraphiQL IDE
-index: 5
----
+# GraphiQL Subscriptions
After setting up your server, you can integrate subscriptions into [GraphiQL](https://github.com/graphql/graphiql/tree/main/packages/graphiql#readme), the in-browser GraphQL IDE.
@@ -37,7 +29,7 @@ After that, you should be able to load the page in your app and see the GraphiQL
## Ably
-To integrate {% internal_link "Ably subscriptions", "subscriptions/ably_implementation" %}, use `createAblyFetcher`, for example:
+To integrate [Ably subscriptions](/subscriptions/ably_implementation), use `createAblyFetcher`, for example:
```js
import Ably from "ably"
@@ -57,7 +49,7 @@ Under the hood, it will use `window.fetch` to send GraphQL operations to the ser
## Pusher
-To integrate {% internal_link "Pusher subscriptions", "subscriptions/pusher_implementation" %}, use `createPusherFetcher`, for example:
+To integrate [Pusher subscriptions](/subscriptions/pusher_implementation), use `createPusherFetcher`, for example:
```js
import Pusher from "pusher-js"
@@ -76,7 +68,7 @@ Under the hood, it will use `window.fetch` to send GraphQL operations to the ser
## ActionCable
-To integrate {% internal_link "ActionCable subscriptions", "subscriptions/action_cable_implementation" %}, use `createActionCableFetcher`, for example:
+To integrate [ActionCable subscriptions](/subscriptions/action_cable_implementation), use `createActionCableFetcher`, for example:
```js
import { createConsumer } from "@rails/actioncable"
diff --git a/guides/javascript_client/overview.md b/guides/javascript_client/overview.md
index 6e9b4f41d81..cad18f2c3af 100644
--- a/guides/javascript_client/overview.md
+++ b/guides/javascript_client/overview.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: Overview
-desc: Getting Started with GraphQL-Ruby's Javascript client, graphql-ruby-client.
-index: 0
----
+# Overview
There is a JavaScript client for GraphQL-Ruby, `graphql-ruby-client`.
@@ -22,9 +14,9 @@ The source code is [in the graphql-ruby repository](https://github.com/rmosolgo/
See detailed guides for more info about its features:
-- {% internal_link "sync CLI", "javascript_client/sync" %} for use with [graphql-pro](https://graphql.pro)'s persisted query backend
+- [sync CLI](/javascript_client/sync) for use with [graphql-pro](https://graphql.pro)'s persisted query backend
- Subscription support:
- - {% internal_link "Apollo integration", "/javascript_client/apollo_subscriptions" %}
- - {% internal_link "Relay integration", "/javascript_client/relay_subscriptions" %}
- - {% internal_link "urql integration", "/javascript_client/urql_subscriptions" %}
- - {% internal_link "GraphiQL integration", "/javascript_client/graphiql_subscriptions" %}
+ - [Apollo integration](/javascript_client/apollo_subscriptions)
+ - [Relay integration](/javascript_client/relay_subscriptions)
+ - [urql integration](/javascript_client/urql_subscriptions)
+ - [GraphiQL integration](/javascript_client/graphiql_subscriptions)
diff --git a/guides/javascript_client/relay_subscriptions.md b/guides/javascript_client/relay_subscriptions.md
index c641ac74c27..c9a5ea256c8 100644
--- a/guides/javascript_client/relay_subscriptions.md
+++ b/guides/javascript_client/relay_subscriptions.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: Relay Subscriptions
-desc: GraphQL subscriptions with GraphQL-Ruby and Relay Modern
-index: 3
----
+# Relay Subscriptions
`graphql-ruby-client` includes three kinds of support for subscriptions with Relay Modern:
@@ -19,11 +11,11 @@ To use it, require `graphql-ruby-client/subscriptions/createRelaySubscriptionHan
__Note:__ For Relay <11, use `import { createLegacyRelaySubscriptionHandler } from "graphql-ruby-client/subscriptions/createRelaySubscriptionHandler"` instead; the signature changed in Relay 11.
-See the {% internal_link "Subscriptions guide", "/subscriptions/overview" %} for information about server-side setup.
+See the [Subscriptions guide](/subscriptions/overview) for information about server-side setup.
## Pusher
-Subscriptions with {% internal_link "Pusher", "/subscriptions/pusher_implementation" %} require two things:
+Subscriptions with [Pusher](/subscriptions/pusher_implementation) require two things:
- A client from the [`pusher-js` library](https://github.com/pusher/pusher-js)
- A [`fetchOperation` function](#fetchoperation-function) for sending the `subscription` operation to the server
@@ -57,7 +49,7 @@ var network = Network.create(fetchQuery, subscriptionHandler)
### Compressed Payloads
-If you're using {% internal_link "compressed payloads", "/subscriptions/pusher_implementation#payload-compression" %}, configure a `decompress:` function, too:
+If you're using [compressed payloads](/subscriptions/pusher_implementation#payload-compression), configure a `decompress:` function, too:
```javascript
// Add `pako` to the project for gunzipping
@@ -79,7 +71,7 @@ var subscriptionHandler = createRelaySubscriptionHandler({
## Ably
-Subscriptions with {% internal_link "Ably", "/subscriptions/ably_implementation" %} require two things:
+Subscriptions with [Ably](/subscriptions/ably_implementation) require two things:
- A client from the [`ably-js` library](https://github.com/ably/ably-js)
- A [`fetchOperation` function](#fetchoperation-function) for sending the `subscription` operation to the server
@@ -113,7 +105,7 @@ var network = Network.create(fetchQuery, subscriptionHandler)
## ActionCable
-With this configuration, `subscription` queries will be routed to {% internal_link "ActionCable", "/subscriptions/action_cable_implementation" %}.
+With this configuration, `subscription` queries will be routed to [ActionCable](/subscriptions/action_cable_implementation).
For example:
@@ -135,7 +127,7 @@ var network = Network.create(fetchQuery, subscriptionHandler)
## With Relay Persisted Queries
-If you're using Relay's built-in [persisted query support](https://relay.dev/docs/guides/persisted-queries/), you can pass `clientName:` to the handler in order to build IDs that work with the {% internal_link "OperationStore", "/operation_store/overview.html" %}. For example:
+If you're using Relay's built-in [persisted query support](https://relay.dev/docs/guides/persisted-queries/), you can pass `clientName:` to the handler in order to build IDs that work with the [OperationStore](/operation_store/overview.html). For example:
```js
var subscriptionHandler = createRelaySubscriptionHandler({
diff --git a/guides/javascript_client/sync.md b/guides/javascript_client/sync.md
index 4d818b017ae..6655c687ac5 100644
--- a/guides/javascript_client/sync.md
+++ b/guides/javascript_client/sync.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: OperationStore Sync
-desc: Javascript tooling for persisted queries with GraphQL-Ruby
-index: 1
----
+# OperationStore Sync
JavaScript support for GraphQL projects using [graphql-pro](https://graphql.pro)'s `OperationStore` for persisted queries.
@@ -21,7 +13,7 @@ JavaScript support for GraphQL projects using [graphql-pro](https://graphql.pro)
- [Plain JS support](#use-with-plain-javascript)
- [Authorization](#authorization)
-See the {% internal_link "OperationStore guide", "/operation_store/overview" %} for server-side setup.
+See the [OperationStore guide](/operation_store/overview) for server-side setup.
## `sync` utility
@@ -42,19 +34,19 @@ Generating client module in app/javascript/graphql/OperationStoreClient.js...
option | description
--------|----------
-`--url` | {% internal_link "Sync API", "/operation_store/getting_started.html#add-routes" %} url
+`--url` | [Sync API](/operation_store/getting_started.html#add-routes) url
`--path` | Local directory to search for `.graphql` / `.graphql.js` files
`--relay-persisted-output` | Path to a `.json` file from `relay-compiler ... --persist-output`
`--apollo-codegen-json-output` | Path to a `.json` file from `apollo client:codegen ... --target json`
`--apollo-android-operation-output` | Path to an `OperationOutput.json` file from Apollo Android
-`--client` | Client ID ({% internal_link "created on server", "/operation_store/client_workflow" %})
-`--secret` | Client Secret ({% internal_link "created on server", "/operation_store/client_workflow" %})
+`--client` | Client ID ([created on server](/operation_store/client_workflow))
+`--secret` | Client Secret ([created on server](/operation_store/client_workflow))
`--outfile` | Destination for generated code
`--outfile-type` | What kind of code to generate (`js` or `json`)
`--header={key}:{value}` | Add a header to the outgoing HTTP request (may be repeated)
`--add-typename` | Add `__typename` to all selection sets (for use with Apollo Client)
`--verbose` | Output some debug information
-`--changeset-version` | Set a {% internal_link "Changeset Version", "/changesets/installation#controller-setup" %} when syncing these queries. (`context[:changeset_version]` will also be required at runtime, when running these stored operations.)
+`--changeset-version` | Set a [Changeset Version](/changesets/installation#controller-setup) when syncing these queries. (`context[:changeset_version]` will also be required at runtime, when running these stored operations.)
`--dump-payload` | A file to write the HTTP Post payload into, or if no filename is passed, then the payload will be written to stdout.
You can see these and a few others with `graphql-ruby-client sync --help`.
@@ -267,7 +259,7 @@ You may also have to __update your app__ to send an identifier, so that the serv
## Use with Apollo Persisted Queries
-Apollo client has a [Persisted Queries Link](https://www.apollographql.com/docs/react/api/link/persisted-queries/). You can use that link with GraphQL-Pro's {% internal_link "OperationStore", "/operation_store/overview" %}. First, create a manifest with [`generate-persisted-query-manifest`](https://www.apollographql.com/docs/react/api/link/persisted-queries/#1-generate-operation-manifests), then, pass the path to that file to `sync`:
+Apollo client has a [Persisted Queries Link](https://www.apollographql.com/docs/react/api/link/persisted-queries/). You can use that link with GraphQL-Pro's [OperationStore](/operation_store/overview). First, create a manifest with [`generate-persisted-query-manifest`](https://www.apollographql.com/docs/react/api/link/persisted-queries/#1-generate-operation-manifests), then, pass the path to that file to `sync`:
```sh
$ graphql-ruby-client sync --apollo-persisted-query-manifest=path/to/manifest.json ...
@@ -316,7 +308,7 @@ $.post("/graphql", {
## Authorization
-`OperationStore` uses HMAC-SHA256 to {% internal_link "authenticate requests" , "/operation_store/access_control" %}.
+`OperationStore` uses HMAC-SHA256 to [authenticate requests](/operation_store/access_control).
Pass the key to `graphql-ruby-client sync` as `--secret` to authenticate it:
diff --git a/guides/javascript_client/urql_subscriptions.md b/guides/javascript_client/urql_subscriptions.md
index 25983705666..53c695f4bd0 100644
--- a/guides/javascript_client/urql_subscriptions.md
+++ b/guides/javascript_client/urql_subscriptions.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: JavaScript Client
-title: urql Subscriptions
-desc: GraphQL subscriptions with GraphQL-Ruby and urql
-index: 4
----
-
-GraphQL-Ruby currently supports using `urql` with the {% internal_link "ActionCable", "/subscriptions/action_cable_implementation" %} and {% internal_link "Pusher implementation", "/subscriptions/pusher_implementation" %}.
+# urql Subscriptions
+
+GraphQL-Ruby currently supports using `urql` with the [ActionCable](/subscriptions/action_cable_implementation) and [Pusher implementation](/subscriptions/pusher_implementation).
## Pusher
@@ -51,4 +43,4 @@ const client = new Client({
});
```
-Want to use `urql` with another subscription backend? Please {% open_an_issue "Using urql with ..." %}.
+Want to use `urql` with another subscription backend? Please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Using+urql+with+...&body=).
diff --git a/guides/js/search.js b/guides/js/search.js
deleted file mode 100644
index 7a9cedcd982..00000000000
--- a/guides/js/search.js
+++ /dev/null
@@ -1,103 +0,0 @@
-var client = algoliasearch('8VO8708WUV', '1f3e2b6f6a503fa82efdec331fd9c55e');
-var index = client.initIndex('prod_graphql_ruby');
-
-var GraphQLRubySearch = {
- // Respond to a change event on `el` by:
- // - Searching the index
- // - Rendering the results
- run: function(el) {
- var searchTerm = el.value
- var searchResults = document.querySelector("#search-results")
- if (!searchTerm) {
- // If there's no search term, clear the results pane
- searchResults.innerHTML = ""
- } else {
- index.search({
- query: searchTerm,
- hitsPerPage: 8,
- }, function(err, content) {
- if (err) {
- console.error(err)
- }
- var results = content.hits
- // Clear the previous results
- searchResults.innerHTML = ""
-
- results.forEach(function(result) {
- // Create a wrapper hyperlink
- var container = document.createElement("a")
- container.className = "search-result"
- container.href = (result.rubydoc_url || result.url) + (result.anchor ? "#" + result.anchor : "")
-
- // This helper will be used to accumulate text into the search-result
- function createSpan(text, className) {
- var txt = document.createElement("span")
- txt.className = className
- txt.innerHTML = text
- container.appendChild(txt)
- }
- if (result.rubydoc_url) {
- createSpan("API Doc", "search-category")
- createSpan(result.title, "search-title")
- } else {
- createSpan(result.section, "search-category")
-
- var resultHeader = [result.title].concat(result.headings).join(" > ")
- createSpan(resultHeader, "search-title")
- var preview = result._snippetResult.content.value
- createSpan(preview, "search-preview")
- }
- searchResults.appendChild(container)
- })
-
- var seeAll = document.createElement("a")
- seeAll.href = "/search?query=" + content.query
- seeAll.className = "search-see-all"
- seeAll.innerHTML = "See All Results (" + content.nbHits + ")"
- searchResults.appendChild(seeAll)
- })
- }
- },
-
- // Return true if we actually highlighted something
- _moveHighlight: function(diff) {
- var allResults = document.querySelectorAll(".search-result")
- var highlightClass = "highlight-search-result"
- if (!allResults.length) {
- // No search results to highlight
- return false
- }
- var highlightedResult = document.querySelector("." + highlightClass)
- var nextHighlightedResult
- var result
- for (var i = 0; i < allResults.length; i++) {
- result = allResults[i]
- if (result == highlightedResult) {
- nextHighlightedResult = allResults[i + diff]
- break
- }
- }
- if (!nextHighlightedResult) {
- // Either nothing was highlighted yet,
- // or we were at the end of results and we loop around
- nextHighlightedResult = allResults[0]
- }
-
- if (highlightedResult) {
- highlightedResult.classList.remove(highlightClass)
- }
- nextHighlightedResult.classList.add(highlightClass)
- nextHighlightedResult.focus()
- return true
- }
-}
-
-document.addEventListener("keydown", function(ev) {
- var diff = ev.keyCode == 38 ? -1 : (ev.keyCode == 40 ? 1 : 0)
- if (diff) {
- var highlighted = GraphQLRubySearch._moveHighlight(diff)
- if (highlighted) {
- ev.preventDefault()
- }
- }
-})
diff --git a/guides/language_tools/c_parser.md b/guides/language_tools/c_parser.md
index 820f3e59e64..f6f766af53f 100644
--- a/guides/language_tools/c_parser.md
+++ b/guides/language_tools/c_parser.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Language Tools
-title: C-based Parser
-desc: The GraphQL::CParser gem is a drop-in replacement for the built-in parser
-index: 1
----
+# C-based Parser
GraphQL-Ruby includes a plain-Ruby parser, but a faster parser is available as a C extension. To use it, add the [`graphql-c_parser` gem](https://rubygems.org/gems/graphql-c_parser) to your project, for example:
@@ -14,7 +6,7 @@ GraphQL-Ruby includes a plain-Ruby parser, but a faster parser is available as a
bundle add graphql-c_parser
```
-When `graphql-c_parser` is `require`d by your app, the C-based parser is installed as the default parser (as {{ "GraphQL.default_parser" | api_doc }}). Bundler requires the library automatically, but you can also require it manually:
+When `graphql-c_parser` is `require`d by your app, the C-based parser is installed as the default parser (as [GraphQL.default_parser](rdoc-ref:GraphQL.default_parser)). Bundler requires the library automatically, but you can also require it manually:
```ruby
require "graphql/c_parser"
diff --git a/guides/language_tools/visitor.md b/guides/language_tools/visitor.md
index f6cb3ce6bda..e2e67266ec2 100644
--- a/guides/language_tools/visitor.md
+++ b/guides/language_tools/visitor.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Language Tools
-title: AST Visitor
-desc: Analyze and modify parsed GraphQL code
-index: 0
----
+# AST Visitor
GraphQL code is usually contained in a string, for example:
@@ -22,14 +14,14 @@ You can perform programmatic analysis and modifications to GraphQL code using a
## Parse
-{{ "GraphQL.parse" | api_doc }} turns a string into a GraphQL document:
+[GraphQL.parse](rdoc-ref:GraphQL.parse) turns a string into a GraphQL document:
```ruby
parsed_doc = GraphQL.parse("{ user(id: \"1\") { userName } }")
# => #
```
-Also, {{ "GraphQL.parse_file" | api_doc }} parses the contents of the named file and includes a `filename` in the parsed document.
+Also, [GraphQL.parse_file](rdoc-ref:GraphQL.parse_file) parses the contents of the named file and includes a `filename` in the parsed document.
#### AST Nodes
@@ -54,14 +46,14 @@ Above, `field_node` is unmodified, but `modified_node` reflects the new name and
## Analyze/Modify
-To inspect or modify a parsed document, extend {{ "GraphQL::Language::Visitor" | api_doc }} and implement its various hooks. It's an implementation of the [visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern). In short, each node of the tree will be "visited" by calling a method, and those methods can gather information and perform modifications.
+To inspect or modify a parsed document, extend [GraphQL::Language::Visitor](rdoc-ref:GraphQL::Language::Visitor) and implement its various hooks. It's an implementation of the [visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern). In short, each node of the tree will be "visited" by calling a method, and those methods can gather information and perform modifications.
In the visitor, each node class has a hook, for example:
-- {{ "GraphQL::Language::Nodes::Field" | api_doc }}s are routed to `#on_field`
-- {{ "GraphQL::Language::Nodes::Argument" | api_doc }}s are routed to `#on_argument`
+- [GraphQL::Language::Nodes::Field](rdoc-ref:GraphQL::Language::Nodes::Field)s are routed to `#on_field`
+- [GraphQL::Language::Nodes::Argument](rdoc-ref:GraphQL::Language::Nodes::Argument)s are routed to `#on_argument`
-See the {{ "GraphQL::Language::Visitor" | api_doc }} API docs for a full list of methods.
+See the [GraphQL::Language::Visitor](rdoc-ref:GraphQL::Language::Visitor) API docs for a full list of methods.
Each method is called with `(node, parent)`, where:
@@ -129,15 +121,15 @@ end
This will add `emailAddress` the fields selection on `node`.
-(These `.add_*` helpers are wrappers around {{ "GraphQL::Language::Nodes::AbstractNode#merge" | api_doc }}.)
+(These `.add_*` helpers are wrappers around [GraphQL::Language::Nodes::AbstractNode#merge](rdoc-ref:GraphQL::Language::Nodes::AbstractNode#merge).)
## Print
-The easiest way to turn an AST back into a string of GraphQL is {{ "GraphQL::Language::Nodes::AbstractNode#to_query_string" | api_doc }}, for example:
+The easiest way to turn an AST back into a string of GraphQL is [GraphQL::Language::Nodes::AbstractNode#to_query_string](rdoc-ref:GraphQL::Language::Nodes::AbstractNode#to_query_string), for example:
```ruby
parsed_doc.to_query_string
# => '{ user(id: "1") { userName } }'
```
-You can also create a subclass of {{ "GraphQL::Language::Printer" | api_doc }} to customize how nodes are printed.
+You can also create a subclass of [GraphQL::Language::Printer](rdoc-ref:GraphQL::Language::Printer) to customize how nodes are printed.
diff --git a/guides/limiters/active_operations.md b/guides/limiters/active_operations.md
index c104523478b..9515e521692 100644
--- a/guides/limiters/active_operations.md
+++ b/guides/limiters/active_operations.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Rate Limiters
-title: Active Operation Limiter
-desc: Limit the number of concurrent GraphQL operations
-index: 2
----
-
-`GraphQL::Enterprise::ActiveOperationLimiter` prevents clients from running too many GraphQL operations at the same time. It uses {% internal_link "Redis", "limiters/redis" %} to track currently-running operations.
+# Active Operation Limiter
+
+`GraphQL::Enterprise::ActiveOperationLimiter` prevents clients from running too many GraphQL operations at the same time. It uses [Redis](/limiters/redis) to track currently-running operations.
## Why?
@@ -39,7 +30,7 @@ end
It also accepts a `stale_request_seconds:` option. The limiter uses that value to clean up request data in case of a crash or other unexpected scenario.
-Before requests will actually be halted, {% internal_link "soft mode", "/limiters/deployment#soft-limits" %} must be disabled.
+Before requests will actually be halted, [soft mode](/limiters/deployment#soft-limits) must be disabled.
#### Query Setup
diff --git a/guides/limiters/deployment.md b/guides/limiters/deployment.md
index 0b2d21c7be7..8849ca7f4e3 100644
--- a/guides/limiters/deployment.md
+++ b/guides/limiters/deployment.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Rate Limiters
-title: Deploying Rate Limiters
-desc: Tips for releasing limiters smoothly
-index: 4
----
+# Deploying Rate Limiters
Here are a few options for deploying GraphQL-Enterprise's rate limiters:
@@ -19,15 +10,15 @@ Here are a few options for deploying GraphQL-Enterprise's rate limiters:
## Dashboard
-Once installed, your {% internal_link "GraphQL-Pro dashboard", "/pro/dashboard" %} will include a simple metrics view:
+Once installed, your [GraphQL-Pro dashboard](/pro/dashboard) will include a simple metrics view:
-{{ "/limiters/active_operation_limiter_dashboard.png" | link_to_img:"GraphQL Active Operation Limiter Dashboard" }}
+
To disable dashboard charts, add `use(... dashboard_charts: false)` to your configuration.
Also, the dashboard includes a link to enable or disable "soft mode":
-{{ "/limiters/soft_button.png" | link_to_img:"GraphQL Rate Limiter Soft Mode Button" }}
+
When "soft mode" is enabled, limited requests are _not_ actually halted (although they are _counted_). When "soft mode" is disabled, any over-limit requests are halted.
@@ -56,7 +47,7 @@ MySchema.enterprise_runtime_limiter.set_soft_limit(false)
## Subscriptions
-If you're using {% internal_link "PusherSubscriptions", "/subscriptions/pusher_implementation" %} or {% internal_link "AblySubscriptions", "/subscriptions/ably_implementation" %}, then you'll need to accomodate subscriptions that were created _before_ you deployed the rate limiter. Those subscriptions are already stored in Redis and their contexts _don't_ include the required `limiter_key:` value.
+If you're using [PusherSubscriptions](/subscriptions/pusher_implementation) or [AblySubscriptions](/subscriptions/ably_implementation), then you'll need to accomodate subscriptions that were created _before_ you deployed the rate limiter. Those subscriptions are already stored in Redis and their contexts _don't_ include the required `limiter_key:` value.
To address this, you can customize the limiter(s) you're using to provide a default value in this case. For example:
diff --git a/guides/limiters/overview.md b/guides/limiters/overview.md
index 260560ed63f..f1739fdf8fe 100644
--- a/guides/limiters/overview.md
+++ b/guides/limiters/overview.md
@@ -1,14 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Rate Limiters
-title: Rate Limiters for GraphQL
-desc: Manage access to your GraphQL API
-index: 0
----
-
+# Rate Limiters for GraphQL
`GraphQL::Enterprise` includes rate limiters built especially for GraphQL.
@@ -21,6 +11,6 @@ There's some overlap in these limiters; both of them constrain the amount of _ti
To get started, read on:
-- {% internal_link "Configure Redis", "limiters/redis" %} for the limiters' backend
-- {% internal_link "Active Operation Limiter", "limiters/active_operations" %}
-- {% internal_link "Runtime Limiter", "limiters/runtime" %}
+- [Configure Redis](/limiters/redis) for the limiters' backend
+- [Active Operation Limiter](/limiters/active_operations)
+- [Runtime Limiter](/limiters/runtime)
diff --git a/guides/limiters/redis.md b/guides/limiters/redis.md
index 43b8df00f26..2af67e479c7 100644
--- a/guides/limiters/redis.md
+++ b/guides/limiters/redis.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Rate Limiters
-title: Configuring Redis
-desc: Preparing the rate limiter backend
-index: 1
----
-
-Rate limiting requires a persistent Redis instance, just like [Sidekiq](https://github.com/mperham/sidekiq/wiki/Using-Redis) or the {% internal_link "Operation Store", "/operation_store/redis_backend" %}. Set `maxmemory-policy noeviction` in `redis.conf` to ensure that Redis doesn't silently drop keys when it reaches its memory limit.
+# Configuring Redis
+
+Rate limiting requires a persistent Redis instance, just like [Sidekiq](https://github.com/mperham/sidekiq/wiki/Using-Redis) or the [Operation Store](/operation_store/redis_backend). Set `maxmemory-policy noeviction` in `redis.conf` to ensure that Redis doesn't silently drop keys when it reaches its memory limit.
## Memory Usage
diff --git a/guides/limiters/runtime.md b/guides/limiters/runtime.md
index 0f2084ccf74..f42a9d79097 100644
--- a/guides/limiters/runtime.md
+++ b/guides/limiters/runtime.md
@@ -1,19 +1,10 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Rate Limiters
-title: Runtime Limiter
-desc: Limit the total runtime of a client's GraphQL Operations
-index: 3
----
-
-`GraphQL::Enterprise::RuntimeLimiter` applies an upper bound to processing time consumed by a single client. It uses {% internal_link "Redis", "limiters/redis" %} track time with a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) algorithm.
+# Runtime Limiter
+
+`GraphQL::Enterprise::RuntimeLimiter` applies an upper bound to processing time consumed by a single client. It uses [Redis](/limiters/redis) track time with a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) algorithm.
## Why?
-This limiter prevents a single client from consuming too much processing time, regardless of whether it comes a burst of short-lived queries (which the {% internal_link "Active Operation Limiter", "/limiters/active_operations" %} can prevent) or a small number of long-running queries. Unlike request counters or complexity calculations, the runtime limiter pays no attention to the structure of the incoming request. Instead, it simply measures the time spent on the request _as a whole_ and halts queries when a client consumes more than the limit.
+This limiter prevents a single client from consuming too much processing time, regardless of whether it comes a burst of short-lived queries (which the [Active Operation Limiter](/limiters/active_operations) can prevent) or a small number of long-running queries. Unlike request counters or complexity calculations, the runtime limiter pays no attention to the structure of the incoming request. Instead, it simply measures the time spent on the request _as a whole_ and halts queries when a client consumes more than the limit.
## Setup
@@ -39,7 +30,7 @@ end
It also accepts a `window_ms:` option, which is the duration over which `limit_ms:` is added to a client's bucket. It defaults to `60_000` (one minute).
-Before requests will actually be halted, {% internal_link "soft mode", "/limiters/deployment#soft-limits" %} must be disabled.
+Before requests will actually be halted, [soft mode](/limiters/deployment#soft-limits) must be disabled.
### Query Setup
@@ -114,4 +105,4 @@ MyMetrics.increment("graphql.runtime_limiter", tags: result.context[:runtime_lim
The limiter will not _interrupt_ a long-running field. Instead, it stops executing new fields after a client exceeds its allowed processing time. This is because interrupting arbitrary code may have unintended consequences for I/O operations, see ["Timeout: Ruby's most dangerous API"](https://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/).
-Also, the limiter only checks remaining time at the _start_ of a query and it only decreases the remaining time at the _end_ of a query. This means that simulaneous queries may consume the remainder at the same time. Use the {% internal_link "Active Operation Limiter", "/limiters/active_operations" %} to limit behavior in this regard. This implementation is basically a trade-off: more granular updates would require more communication with Redis which would add overhead to each request.
+Also, the limiter only checks remaining time at the _start_ of a query and it only decreases the remaining time at the _end_ of a query. This means that simulaneous queries may consume the remainder at the same time. Use the [Active Operation Limiter](/limiters/active_operations) to limit behavior in this regard. This implementation is basically a trade-off: more granular updates would require more communication with Redis which would add overhead to each request.
diff --git a/guides/mutations/mutation_authorization.md b/guides/mutations/mutation_authorization.md
index f5b08c0f9f5..fd7d46cce53 100644
--- a/guides/mutations/mutation_authorization.md
+++ b/guides/mutations/mutation_authorization.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Mutations
-title: Mutation authorization
-desc: Checking permissions for mutations
-index: 3
----
+# Mutation authorization
Before running a mutation, you probably want to do a few things:
@@ -57,7 +49,7 @@ end
Now, when any non-`admin` user tries to run the mutation, it won't run. Instead, they'll get an error in the response.
-Additionally, `#ready?` may return `false, { ... }` to return {% internal_link "errors as data", "/mutations/mutation_errors.html#errors-as-data" %}:
+Additionally, `#ready?` may return `false, { ... }` to return [errors as data](/mutations/mutation_errors.html#errors-as-data):
```ruby
def ready?
@@ -93,9 +85,9 @@ end
It works like this: if you pass a `loads:` option, it will:
- Automatically remove `_id` from the name and pass that name for the `as:` option
-- Add a prepare hook to fetch an object with the given `ID` (using {{ "Schema.object_from_id" | api_doc }})
-- Check that the fetched object's type matches the `loads:` type (using {{ "Schema.resolve_type" | api_doc }})
-- Run the fetched object through its type's `.authorized?` hook (see {% internal_link "Authorization", "/authorization/authorization" %})
+- Add a prepare hook to fetch an object with the given `ID` (using [Schema.object_from_id](rdoc-ref:GraphQL::Schema.object_from_id))
+- Check that the fetched object's type matches the `loads:` type (using [Schema.resolve_type](rdoc-ref:GraphQL::Schema.resolve_type))
+- Run the fetched object through its type's `.authorized?` hook (see [Authorization](/authorization/authorization))
- Inject it into `#resolve` using the object-style name (`employee:`)
In this case, if the argument value is provided by `object_from_id` doesn't return a value, the mutation will fail with an error.
@@ -133,7 +125,7 @@ When `#authorized?` returns `false` (or something falsey), the mutation will be
#### Adding errors
-To add errors as data (as described in {% internal_link "Mutation errors", "/mutations/mutation_errors.html#errors-as-data" %}), return a value _along with_ `false`, for example:
+To add errors as data (as described in [Mutation errors](/mutations/mutation_errors.html#errors-as-data)), return a value _along with_ `false`, for example:
```ruby
def authorized?(employee:)
diff --git a/guides/mutations/mutation_classes.md b/guides/mutations/mutation_classes.md
index 513ce24c968..064910402f8 100644
--- a/guides/mutations/mutation_classes.md
+++ b/guides/mutations/mutation_classes.md
@@ -1,15 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Mutations
-title: Mutation Classes
-desc: Use mutation classes to implement behavior, then hook them up to your schema.
-index: 1
-redirect_from:
- - /queries/mutations/
- - /relay/mutations/
----
+# Mutation Classes
GraphQL _mutations_ are special fields: instead of reading data or performing calculations, they may _modify_ the application state. For example, mutation fields may:
@@ -28,14 +17,14 @@ Like all GraphQL fields, mutation fields:
GraphQL-Ruby includes two classes to help you write mutations:
-- {{ "GraphQL::Schema::Mutation" | api_doc }}, a bare-bones base class
-- {{ "GraphQL::Schema::RelayClassicMutation" | api_doc }}, a base class with a set of nice conventions that also supports the Relay Classic mutation specification.
+- [GraphQL::Schema::Mutation](rdoc-ref:GraphQL::Schema::Mutation), a bare-bones base class
+- [GraphQL::Schema::RelayClassicMutation](rdoc-ref:GraphQL::Schema::RelayClassicMutation), a base class with a set of nice conventions that also supports the Relay Classic mutation specification.
-Besides those, you can also use the plain {% internal_link "field API", "/type_definitions/objects#fields" %} to write mutation fields.
+Besides those, you can also use the plain [field API](/type_definitions/objects#fields) to write mutation fields.
## Example mutation class
-If you used the {% internal_link "install generator", "/schema/generators#graphqlinstall" %}, a base mutation class will already have been generated for you. If that's not the case, you should add a base class to your application, for example:
+If you used the [install generator](/schema/generators#graphqlinstall), a base mutation class will already have been generated for you. If that's not the case, you should add a base class to your application, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
@@ -82,7 +71,7 @@ end
The `#resolve` method should return a hash whose symbols match the `field` names.
-(See {% internal_link "Mutation Errors", "/mutations/mutation_errors" %} for more information about returning errors.)
+(See [Mutation Errors](/mutations/mutation_errors) for more information about returning errors.)
Also, you can configure `null(false)` in your mutation class to make the generated payload class non-null.
@@ -118,7 +107,7 @@ class Mutations::AddStar < Mutations::BaseMutation
end
```
-By specifying that the `post_id` argument loads a `Types::Post` object type, a `Post` object will be loaded via {% internal_link "`Schema.object_from_id`", "/schema/definition.html#object-identification" %} with the provided `post_id`.
+By specifying that the `post_id` argument loads a `Types::Post` object type, a `Post` object will be loaded via [`Schema.object_from_id`](/schema/definition.html#object-identification) with the provided `post_id`.
All arguments that end in `_id` and use the `loads:` method will have their `_id` suffix removed. For example, the mutation resolver above receives a `post` argument which contains the loaded object, instead of a `post_id` argument.
@@ -164,11 +153,11 @@ In the above examples, `loads:` is provided a concrete type, but it also support
### Resolving the type of loaded objects
-When `loads:` gets an object from {{ "Schema.object_from_id" | api_doc }}, it passes that object to {{ "Schema.resolve_type" | api_doc }} to confirm that it resolves to the same type originally configured with `loads:`.
+When `loads:` gets an object from [Schema.object_from_id](rdoc-ref:GraphQL::Schema.object_from_id), it passes that object to [Schema.resolve_type](rdoc-ref:GraphQL::Schema.resolve_type) to confirm that it resolves to the same type originally configured with `loads:`.
### Handling failed loads
-If `loads:` fails to find an object or if the loaded object isn't resolved to the specified `loads:` type (using {{ "Schema.resolve_type" | api_doc }}), a {{ "GraphQL::LoadApplicationObjectFailedError" | api_doc }} is raised and returned to the client.
+If `loads:` fails to find an object or if the loaded object isn't resolved to the specified `loads:` type (using [Schema.resolve_type](rdoc-ref:GraphQL::Schema.resolve_type)), a [GraphQL::LoadApplicationObjectFailedError](rdoc-ref:GraphQL::LoadApplicationObjectFailedError) is raised and returned to the client.
You can customize this behavior by implementing `def load_application_object_failed` in your mutation class, for example:
@@ -182,7 +171,7 @@ Or, if `load_application_object_failed` returns a new object, that object will b
### Handling unauthorized loaded objects
-When an object is _loaded_ but fails its {% internal_link "`.authorized?` check", "/authorization/authorization#object-authorization" %}, a {{ "GraphQL::UnauthorizedError" | api_doc }} is raised. By default, it's passed to {{ "Schema.unauthorized_object" | api_doc }} (see {% internal_link "Handling Unauthorized Objects", "/authorization/authorization.html#handling-unauthorized-objects" %}). You can customize this behavior by implementing `def unauthorized_object(err)` in your mutation, for example:
+When an object is _loaded_ but fails its [`.authorized?` check](/authorization/authorization#object-authorization), a [GraphQL::UnauthorizedError](rdoc-ref:GraphQL::UnauthorizedError) is raised. By default, it's passed to [Schema.unauthorized_object](rdoc-ref:GraphQL::Schema.unauthorized_object) (see [Handling Unauthorized Objects](/authorization/authorization.html#handling-unauthorized-objects)). You can customize this behavior by implementing `def unauthorized_object(err)` in your mutation, for example:
```ruby
def unauthorized_object(error)
diff --git a/guides/mutations/mutation_errors.md b/guides/mutations/mutation_errors.md
index 6d1f74cd363..8e041c60d8c 100644
--- a/guides/mutations/mutation_errors.md
+++ b/guides/mutations/mutation_errors.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Mutations
-title: Mutation errors
-desc: Tips for handling and returning errors from mutations
-index: 2
----
+# Mutation errors
How can you handle errors inside mutations? Let's explore a couple of options.
diff --git a/guides/mutations/mutation_root.md b/guides/mutations/mutation_root.md
index 08141ea8b32..4b9b7de4e8b 100644
--- a/guides/mutations/mutation_root.md
+++ b/guides/mutations/mutation_root.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Mutations
-title: Mutation Root
-desc: The Mutation object is the entry point for mutation operations.
-index: 0
----
+# Mutation Root
GraphQL mutations all begin with the `mutation` keyword:
@@ -41,4 +33,4 @@ end
Now, whenever an incoming request uses the `mutation` keyword, it will go to `Mutation`.
-See {% internal_link "Mutation Classes", "/mutations/mutation_classes" %} for some helpers to define mutation fields.
+See [Mutation Classes](/mutations/mutation_classes) for some helpers to define mutation fields.
diff --git a/guides/object_cache/caching.md b/guides/object_cache/caching.md
index 1d39b94b14e..66edb154e50 100644
--- a/guides/object_cache/caching.md
+++ b/guides/object_cache/caching.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: Caching Results
-desc: Configuration options for caching objects and fields
-index: 2
----
+# Caching Results
`GraphQL::Enterprise::ObjectCache` supports several different caching configurations for objects and fields. To get started, include the extension in your base object class and base field class and use `cacheable(...)` to set up the default cache behavior:
@@ -57,7 +48,7 @@ Only _queries_ are cached. `ObjectCache` skips mutations and subscriptions altog
## `public:`
-`cacheable(public: false)` means that a type or field may be _cached_, but {% internal_link "`Schema.private_context_fingerprint_for(ctx)`", "/object_cache/schema_setup#context-fingerprint" %} should be included in its cache key. In practice, this means that each client can have its own cached responses. Any query that contains a `cacheable(public: false)` type or field will use a private cache key.
+`cacheable(public: false)` means that a type or field may be _cached_, but [`Schema.private_context_fingerprint_for(ctx)`](/object_cache/schema_setup#context-fingerprint) should be included in its cache key. In practice, this means that each client can have its own cached responses. Any query that contains a `cacheable(public: false)` type or field will use a private cache key.
`cacheable(public: true)` means that cached values from this type or field may be shared by _all_ clients. Use this for public-facing data which is the same for all viewers. Queries that include _only_ `public: true` types and fields will not include `Schema.private_context_fingerprint_for(ctx)` in their cache keys. That way their responses will be shared by all clients who request them.
@@ -126,7 +117,7 @@ class Query < GraphQL::Schema::Object
end
```
-If you're using {{ "GraphQL::Schema::Resolver" | api_doc }}, you'd call `.items_for` slightly differently:
+If you're using [GraphQL::Schema::Resolver](rdoc-ref:GraphQL::Schema::Resolver), you'd call `.items_for` slightly differently:
```ruby
def resolve(division: nil)
@@ -174,7 +165,7 @@ By default, connection-related objects (like `*Connection` and `*Edge` types) "i
## Caching Introspection
-By default, introspection fields are considered _public_ for all queries. This means that they are considered cacheable and their results will be reused for any clients who request them. When {% internal_link "adding the ObjectCache to your schema", "/object_cache/schema_setup#add-the-cache", %}, you can provide some options to customize this behavior:
+By default, introspection fields are considered _public_ for all queries. This means that they are considered cacheable and their results will be reused for any clients who request them. When [adding the ObjectCache to your schema](/object_cache/schema_setup#add-the-cache), you can provide some options to customize this behavior:
- `cache_introspection: { public: false, ... }` to use [`public: false`](#public) for all introspection fields. Use this if you hide schema members for some clients.
- `cache_introspection: false` to completely disable caching on introspection fields.
diff --git a/guides/object_cache/memcached.md b/guides/object_cache/memcached.md
index 7ab0b9af266..fbf5144c38a 100644
--- a/guides/object_cache/memcached.md
+++ b/guides/object_cache/memcached.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: Dalli Configuration
-desc: Setting up the Memcached backend
-index: 3
----
+# Dalli Configuration
`GraphQL::Enterprise::ObjectCache` can also run with a Memcached backend via the [Dalli](https://github.com/petergoldstein/dalli) client gem.
diff --git a/guides/object_cache/overview.md b/guides/object_cache/overview.md
index d04d93e648f..3bb84ea9010 100644
--- a/guides/object_cache/overview.md
+++ b/guides/object_cache/overview.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: GraphQL ObjectCache
-desc: A server-side cache for GraphQL-Ruby
-index: 0
----
-
-`GraphQL::Enterprise::ObjectCache` is an application-level cache for GraphQL-Ruby servers. It works by storing a {% internal_link "_cache fingerprint_ for each object", "/object_cache/schema_setup#object-fingerprint" %} in a query, then serving a cached response as long as those fingerprints don't change. The cache can also be customized with {% internal_link "TTLs", "/object_cache/caching#ttl" %}.
+# GraphQL ObjectCache
+
+`GraphQL::Enterprise::ObjectCache` is an application-level cache for GraphQL-Ruby servers. It works by storing a [_cache fingerprint_ for each object](/object_cache/schema_setup#object-fingerprint) in a query, then serving a cached response as long as those fingerprints don't change. The cache can also be customized with [TTLs](/object_cache/caching#ttl).
## Why?
@@ -18,20 +9,20 @@ index: 0
Usually, a GraphQL query alternates between data fetching and calling application logic:
-{{ "/object_cache/query-without-cache.png" | link_to_img:"GraphQL-Ruby profile, without caching" }}
+
But with `ObjectCache`, it checks the cache first, returning a cached response if possible:
-{{ "/object_cache/query-with-cache.png" | link_to_img:"GraphQL-Ruby profile, with ObjectCache" }}
+
This reduces latency for clients and reduces the load on your database and application server.
## How
-Before running a query, `ObjectCache` creates a fingerprint for the query using {{ "GraphQL::Query#fingerprint" | api_doc }} and {% internal_link "`Schema.context_fingerprint_for(ctx)`", "/object_cache/schema_setup#context-fingerprint" %}. Then, it checks the backend for a cached response which matches the fingerprint.
+Before running a query, `ObjectCache` creates a fingerprint for the query using [GraphQL::Query#fingerprint](rdoc-ref:GraphQL::Query#fingerprint) and [`Schema.context_fingerprint_for(ctx)`](/object_cache/schema_setup#context-fingerprint). Then, it checks the backend for a cached response which matches the fingerprint.
-If a match is found, the `ObjectCache` fetches the objects previously visited by this query. Then, it compares the current fingerprint of each object ot the one in the cache and checks `.authorized?` for that object. If the fingerprints all match and all objects pass authorization checks, then the cached response returned. (Authorization checks can be {% internal_link "disabled", "/object_cache/schema_setup#disabling-reauthorization" %}.)
+If a match is found, the `ObjectCache` fetches the objects previously visited by this query. Then, it compares the current fingerprint of each object ot the one in the cache and checks `.authorized?` for that object. If the fingerprints all match and all objects pass authorization checks, then the cached response returned. (Authorization checks can be [disabled](/object_cache/schema_setup#disabling-reauthorization).)
If there is no cached response or if the fingerprints don't match, then the incoming query is re-evaluated. While it's executed, `ObjectCache` gathers the IDs and fingerprints of each object it encounters. When the query is done, the result and the new object fingerprints are written to the cache.
@@ -39,7 +30,7 @@ If there is no cached response or if the fingerprints don't match, then the inco
To get started with the object cache:
-- {% internal_link "Prepare the schema", "/object_cache/schema_setup" %}
-- Set up a {% internal_link "Redis backend", "/object_cache/redis" %} or {% internal_link "Memcached backend", "/object_cache/memcached" %}
-- {% internal_link "Configure types and fields for caching", "/object_cache/caching" %}
-- Check out the {% internal_link "runtime considerations", "/object_cache/runtime_considerations" %}
+- [Prepare the schema](/object_cache/schema_setup)
+- Set up a [Redis backend](/object_cache/redis) or [Memcached backend](/object_cache/memcached)
+- [Configure types and fields for caching](/object_cache/caching)
+- Check out the [runtime considerations](/object_cache/runtime_considerations)
diff --git a/guides/object_cache/redis.md b/guides/object_cache/redis.md
index 9d352ed84a1..5baf01c66ae 100644
--- a/guides/object_cache/redis.md
+++ b/guides/object_cache/redis.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: Redis Configuration
-desc: Setting up the Redis backend
-index: 3
----
+# Redis Configuration
`GraphQL::Enterprise::ObjectCache` requires a Redis connection to store cached responses. Unlike `OperationStore` or rate limiters, this Redis instance should be configured to evict keys as needed.
diff --git a/guides/object_cache/runtime_considerations.md b/guides/object_cache/runtime_considerations.md
index 4eb959a8ae0..7d3d482e6b3 100644
--- a/guides/object_cache/runtime_considerations.md
+++ b/guides/object_cache/runtime_considerations.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: Runtime Considerations
-desc: Settings and observability per-query
-index: 4
----
+# Runtime Considerations
With caching configured, here are a few more things to keep in mind while queries are running.
@@ -64,4 +55,4 @@ pp result.context[:object_cache]
If you need to manually clear the cache for a query, pass `context: { refresh_object_cache: true, ... }`. This will cause the `ObjectCache` to remove the already-cached result (if there was one), reassess the query for cache validity, and return a freshly-executed result.
-Usually, this shouldn't be necessary; making sure objects update their {% internal_link "cache fingerprints", "/object_cache/schema_setup.html#object-fingerprint" %} will cause entries to expire when they should be re-executed. See also {% internal_link "Schema fingerprint", "/object_cache/schema_setup.html#schema-fingerprint" %} for expiring _all_ results in the cache.
+Usually, this shouldn't be necessary; making sure objects update their [cache fingerprints](/object_cache/schema_setup.html#object-fingerprint) will cause entries to expire when they should be re-executed. See also [Schema fingerprint](/object_cache/schema_setup.html#schema-fingerprint) for expiring _all_ results in the cache.
diff --git a/guides/object_cache/schema_setup.md b/guides/object_cache/schema_setup.md
index 9d28e46c1b6..8c925d49fc6 100644
--- a/guides/object_cache/schema_setup.md
+++ b/guides/object_cache/schema_setup.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-enterprise: true
-section: GraphQL Enterprise - Object Cache
-title: Schema Setup
-desc: Prepare your schema to serve cached responses
-index: 1
----
+# Schema Setup
To prepare the schema to serve cached responses, you have to add `GraphQL::Enterprise::ObjectCache` and implement a few hooks.
@@ -21,13 +12,13 @@ class MySchema < GraphQL::Schema
end
```
-See the {% internal_link "Redis guide", "/object_cache/redis" %} or {% internal_link "Memcached guide", "/object_cache/memcached" %} for details about configuring cache storage.
+See the [Redis guide](/object_cache/redis) or [Memcached guide](/object_cache/memcached) for details about configuring cache storage.
-Additionally, it accepts some options for customizing how introspection is cached, see {% internal_link "Caching Introspection", "/object_cache/caching#caching-introspection" %}
+Additionally, it accepts some options for customizing how introspection is cached, see [Caching Introspection](/object_cache/caching#caching-introspection)
## Context Fingerprint
-Additionally, you should implement `def self.private_context_fingerprint_for(context)` to return a string identifying the private scope of the given context. This method will be called whenever a query includes a {% internal_link "`public: false` type or field", "/object_cache/caching#public" %}. For example:
+Additionally, you should implement `def self.private_context_fingerprint_for(context)` to return a string identifying the private scope of the given context. This method will be called whenever a query includes a [`public: false` type or field](/object_cache/caching#public). For example:
```ruby
class MySchema < GraphQL::Schema
@@ -73,7 +64,7 @@ class MySchema < GraphQL::Schema
end
```
-The returned strings are used as cache keys in the database -- whenever they change, stale data is left to be {% internal_link "cleaned up by Redis", "/object_cache/redis#memory-management" %}.
+The returned strings are used as cache keys in the database -- whenever they change, stale data is left to be [cleaned up by Redis](/object_cache/redis#memory-management).
## Object Identification
@@ -83,7 +74,7 @@ The returned strings are used as cache keys in the database -- whenever they cha
- `def self.object_from_id(id, context)` which returns the application object for the given globally-unique `id`
- `def self.resolve_type(abstract_type, object, context)` which returns a GraphQL object type definition to use for `object`
-After your schema is setup, you can {% internal_link "configure caching on your types and fields", "/object_cache/caching", %}.
+After your schema is setup, you can [configure caching on your types and fields](/object_cache/caching).
## Schema Fingerprint
diff --git a/guides/operation_store/access_control.md b/guides/operation_store/access_control.md
index f4a714fea9f..c5ed2ec2cb4 100644
--- a/guides/operation_store/access_control.md
+++ b/guides/operation_store/access_control.md
@@ -1,19 +1,10 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Access Control
-desc: Manage authentication & visibility for your OperationStore server.
-index: 6
-pro: true
----
+# Access Control
The `OperationStore` has a built-in mechanism for authenticating incoming `sync` requests. This way, you can be sure that all registered queries came from legitimate sources.
## Authentication
-When you [add a client]({{ site.base_url }}/operation_store/client_workflow#add-a-client), you also associate a _secret_ with that client. You can use the default or provide your own and you can update a client secret at any time. By updating a secret, old secrets become invalid.
+When you [add a client](/operation_store/client_workflow#add-a-client), you also associate a _secret_ with that client. You can use the default or provide your own and you can update a client secret at any time. By updating a secret, old secrets become invalid.
This secret is used to add an authorization header, generated with HMAC-SHA256. With this header, the server can assert:
@@ -28,4 +19,4 @@ The Authorization header takes the form:
"GraphQL::Pro #{client_name} #{hmac}"
```
-{% internal_link "graphql-ruby-client", "/javascript_client/sync" %} adds this header to outgoing requests by using the provided `--client` and `--secret` values.
+[graphql-ruby-client](/javascript_client/sync) adds this header to outgoing requests by using the provided `--client` and `--secret` values.
diff --git a/guides/operation_store/active_record_backend.md b/guides/operation_store/active_record_backend.md
index 8b36454343b..53d2bee48e5 100644
--- a/guides/operation_store/active_record_backend.md
+++ b/guides/operation_store/active_record_backend.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: ActiveRecord Backend
-desc: Storing persisted queries with ActiveRecord
-index: 2
-pro: true
----
+# ActiveRecord Backend
GraphQL-Pro's `OperationStore` can use ActiveRecord to store persisted queries. After setting up the database, it will read and write using those tables as needed.
diff --git a/guides/operation_store/client_workflow.md b/guides/operation_store/client_workflow.md
index 422375ec52f..7f915d45678 100644
--- a/guides/operation_store/client_workflow.md
+++ b/guides/operation_store/client_workflow.md
@@ -1,55 +1,46 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Client Workflow
-desc: Add clients to the system, then sync their operations with the database.
-index: 4
-pro: true
----
+# Client Workflow
To use persisted queries with your client application, you must:
-- Set up `OperationStore`, as described in {% internal_link "Getting Started","/operation_store/getting_started" %}
+- Set up `OperationStore`, as described in [Getting Started](/operation_store/getting_started)
- [Add the client](#add-a-client) to the system
- [Sync operations](#syncing) from the client to the server
- [Send `params[:operationId]`](#client-usage) from the client app
-This documentation also touches on {% internal_link "graphql-ruby-client sync", "/javascript_client/sync" %}, a JavaScript client library for using `OperationStore`.
+This documentation also touches on [graphql-ruby-client sync](/javascript_client/sync), a JavaScript client library for using `OperationStore`.
## Add a Client
-Clients are registered via {% internal_link "the dashboard","/operation_store/getting_started#add-routes" %}:
+Clients are registered via [the dashboard](/operation_store/getting_started#add-routes):
-{{ "/operation_store/add_a_client.png" | link_to_img:"Add a Client for Persisted Queries" }}
+
-A default `secret` is provided for you, but you can also enter your own. The `secret` is used for {% internal_link "HMAC authentication", "/operation_store/access_control" %}.
+A default `secret` is provided for you, but you can also enter your own. The `secret` is used for [HMAC authentication](/operation_store/access_control).
-(Are you interested in a Ruby API for this? Please {% open_an_issue "OperationStore Ruby API" %} or email `support@graphql.pro`.)
+(Are you interested in a Ruby API for this? Please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=OperationStore+Ruby+API&body=) or email `support@graphql.pro`.)
## Syncing
-Once a client is registered, it can push queries to the server via {% internal_link "the Sync API","/operation_store/getting_started#add-routes" %}.
+Once a client is registered, it can push queries to the server via [the Sync API](/operation_store/getting_started#add-routes).
-The easiest way to sync is with `graphql-ruby-client sync`, a command-line tool written in JavaScript ({% internal_link "Sync Guide", "/javascript_client/sync" %})
+The easiest way to sync is with `graphql-ruby-client sync`, a command-line tool written in JavaScript ([Sync Guide](/javascript_client/sync))
In short, it:
- Finds GraphQL queries from `.graphql` files or `relay-compiler` output in the provided `--path`
-- Adds an {% internal_link "Authentication header","/operation_store/access_control" %} based on the provided `--client` and `--secret`
+- Adds an [Authentication header](/operation_store/access_control) based on the provided `--client` and `--secret`
- Sends the operations to the provided `--url`
- Generates a JavaScript module into the provided `--outfile`
For example:
-{{ "/operation_store/sync_example.png" | link_to_img:"OperationStore client sync" }}
+
-For help syncing in another language, you can take inspiration from the [JavaScript implementation](https://github.com/rmosolgo/graphql-ruby/tree/master/javascript_client), {% open_an_issue "Implementing operation sync in another language" %}, or email `support@graphql.pro`.
+For help syncing in another language, you can take inspiration from the [JavaScript implementation](https://github.com/rmosolgo/graphql-ruby/tree/master/javascript_client), [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Implementing+operation+sync+in+another+language&body=), or email `support@graphql.pro`.
## Client Usage
-See the {% internal_link "Sync Guide", "/javascript_client/sync" %} for using OperationStore with Relay Modern, Apollo 1.x, Apollo Link, or plain JavaScript.
+See the [Sync Guide](/javascript_client/sync) for using OperationStore with Relay Modern, Apollo 1.x, Apollo Link, or plain JavaScript.
To run stored operations from another client, send a param called `operationId` which is composed of:
@@ -66,4 +57,4 @@ The server will use those values to fetch an operation from the database.
### Next Steps
-Learn more about `OperationStore`'s {% internal_link "authentication", "/operation_store/access_control" %} or read some tips for {% internal_link "server management","/operation_store/server_management" %}.
+Learn more about `OperationStore`'s [authentication](/operation_store/access_control) or read some tips for [server management](/operation_store/server_management).
diff --git a/guides/operation_store/getting_started.md b/guides/operation_store/getting_started.md
index 9303cac183f..b20aa5e38ca 100644
--- a/guides/operation_store/getting_started.md
+++ b/guides/operation_store/getting_started.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Getting Started
-desc: Add GraphQL::Pro::OperationStore to your app
-index: 1
-pro: true
----
+# Getting Started
To use `GraphQL::Pro::OperationStore` with your app, follow these steps:
@@ -16,20 +7,20 @@ To use `GraphQL::Pro::OperationStore` with your app, follow these steps:
- [Add `OperationStore`](#add-operationstore) to your GraphQL schema
- [Add routes](#add-routes) for the Dashboard and sync API
- [Update your controller](#update-the-controller) to support persisted queries
-- {% internal_link "Add a client","/operation_store/client_workflow" %} to start syncing queries
+- [Add a client](/operation_store/client_workflow) to start syncing queries
## Dependencies
`OperationStore` requires two gems in your application environment:
-- {% internal_link "ActiveRecord", "/operation_store/active_record_backend" %} or {% internal_link "Redis", "/operation_store/redis_backend" %} for persistence. (Using another ORM or backend? Please {% open_an_issue "Backend support request for OperationStore" %} to request support!)
+- [ActiveRecord](/operation_store/active_record_backend) or [Redis](/operation_store/redis_backend) for persistence. (Using another ORM or backend? Please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Backend+support+request+for+OperationStore&body=) to request support!)
- `Rack`: to serve the Dashboard and Sync API. (In Rails, this is provided by `config/routes.rb`.)
These are bundled with Rails by default.
## Prepare the Database
-If you're going to store data with ActiveRecord, {% internal_link "migrate the database", "/operation_store/active_record_backend" %} to prepare tables for it.
+If you're going to store data with ActiveRecord, [migrate the database](/operation_store/active_record_backend) to prepare tables for it.
## Add `OperationStore`
@@ -44,11 +35,11 @@ class MySchema < GraphQL::Schema
end
```
-Make sure to add this feature _after_ other {% internal_link "Tracing", "/queries/tracing" %}-based features so that those other features will have access to the loaded query string. Otherwise, you may get `"No query string was present"` errors.
+Make sure to add this feature _after_ other [Tracing](/queries/tracing)-based features so that those other features will have access to the loaded query string. Otherwise, you may get `"No query string was present"` errors.
By default, it uses `ActiveRecord`. It also accepts:
-- `redis:`, for using a {% internal_link "Redis backend", "/operation_store/redis_backend" %}; OR
+- `redis:`, for using a [Redis backend](/operation_store/redis_backend); OR
- `backend_class:`, for implementing custom persistence.
Also, you can disable updates to "last used at" with `default_touch_last_used_at: false`. (This can also be configured per-query with `context[:operation_store_touch_last_used_at] = true|false`.)
@@ -73,11 +64,11 @@ Rails.application.routes.draw do
end
```
-`MySchema.operation_store_sync` receives pushes from clients. See {% internal_link "Client Workflow","/operation_store/client_workflow" %} for more info on how this endpoint is used.
+`MySchema.operation_store_sync` receives pushes from clients. See [Client Workflow](/operation_store/client_workflow) for more info on how this endpoint is used.
-`MySchema.dashboard` includes a web view to the `OperationStore`, visible at `/graphql/dashboard`. See the {% internal_link "Dashboard guide", "/pro/dashboard" %} for more details, including authorization.
+`MySchema.dashboard` includes a web view to the `OperationStore`, visible at `/graphql/dashboard`. See the [Dashboard guide](/pro/dashboard) for more details, including authorization.
-{{ "/operation_store/graphql_ui.png" | link_to_img:"GraphQL Persisted Operations Dashboard" }}
+
`operation_store_sync` and `dashboard` are both Rack apps, so you can mount them in Rails, Sinatra, or any other Rack app.
@@ -92,7 +83,7 @@ mount lazy_routes.operation_store_sync, at: "/graphql/sync"
### With Visibility Profiles
-You can apply a {% internal_link "visibility profile", "/authorization/visibility#visibility-profiles" %} to incoming operations by passing the profile name to `operation_store_sync`, for example:
+You can apply a [visibility profile](/authorization/visibility#visibility-profiles) to incoming operations by passing the profile name to `operation_store_sync`, for example:
```ruby
mount MySchema.operation_store_sync(visibility_profile: :public_api), at: "/graphql/sync"
@@ -123,8 +114,8 @@ MySchema.execute(
`OperationStore` will use `operation_id` to fetch the operation from the database.
-See {% internal_link "Server Management","/operation_store/server_management" %} for details about rejecting GraphQL from `params[:query]`.
+See [Server Management](/operation_store/server_management) for details about rejecting GraphQL from `params[:query]`.
## Next Steps
-Sync your operations with the {% internal_link "Client Workflow","/operation_store/client_workflow" %}.
+Sync your operations with the [Client Workflow](/operation_store/client_workflow).
diff --git a/guides/operation_store/overview.md b/guides/operation_store/overview.md
index 0b8cc5995d2..6679c2f845b 100644
--- a/guides/operation_store/overview.md
+++ b/guides/operation_store/overview.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Overview
-desc: Learn how persisted queries work and how OperationStore implements them.
-index: 0
-pro: true
----
-
-`GraphQL::Pro::OperationStore` uses `Rack` and a storage backend ({% internal_link "ActiveRecord", "/operation_store/active_record_backend" %} or {% internal_link "Redis", "/operation_store/redis_backend" %}) to maintain a normalized, deduplicated database of _persisted queries_ for your GraphQL system.
+# Overview
+
+`GraphQL::Pro::OperationStore` uses `Rack` and a storage backend ([ActiveRecord](/operation_store/active_record_backend) or [Redis](/operation_store/redis_backend)) to maintain a normalized, deduplicated database of _persisted queries_ for your GraphQL system.
In this guide, you'll find:
@@ -19,10 +10,10 @@ In this guide, you'll find:
In other guides, you can read more about:
-- {% internal_link "Getting Started","/operation_store/getting_started" %} installing `OperationStore` in your app
-- {% internal_link "Workflow","/operation_store/client_workflow" %} and usage for client apps
-- {% internal_link "Authentication","/operation_store/access_control" %} for the sync API
-- {% internal_link "Server Management","/operation_store/server_management" %} after your system is running
+- [Getting Started](/operation_store/getting_started) installing `OperationStore` in your app
+- [Workflow](/operation_store/client_workflow) and usage for client apps
+- [Authentication](/operation_store/access_control) for the sync API
+- [Server Management](/operation_store/server_management) after your system is running
Also, you can find a [demo app on GitHub](https://github.com/rmosolgo/graphql-pro-operation-store-example).
@@ -88,23 +79,23 @@ Persisted queries improve the _efficiency_ of your system by reducing HTTP traff
For example, _before_ using persisted queries, the entire query is sent to the server:
-{{ "/operation_store/request_before.png" | link_to_img:"GraphQL request without persisted queries" }}
+
But _after_ using persisted queries, only the query identification info is sent to the server:
-{{ "/operation_store/request_after.png" | link_to_img:"GraphQL request with persisted queries" }}
+
### Visibility
Persisted queries improve _visibility_ because you can track GraphQL usage from a single location. `OperationStore` maintains an index of type, field and argument usage so that you can analyze your traffic.
-{{ "/operation_store/operation_index.png" | link_to_img:"Index of GraphQL usage with persisted queries" }}
+
## How it Works
`OperationStore` uses tables in your database to store normalized, deduplicated GraphQL strings. The database is immutable: new operations may be added, but operations are never modified or removed.
-When clients {% internal_link "sync their operations","/operation_store/client_workflow" %}, requests are {% internal_link "authenticated","/operation_store/access_control" %}, then the incoming GraphQL is validated, normalized, and added to the database if needed. Also, the incoming client name is associated with all operations in the payload.
+When clients [sync their operations](/operation_store/client_workflow), requests are [authenticated](/operation_store/access_control), then the incoming GraphQL is validated, normalized, and added to the database if needed. Also, the incoming client name is associated with all operations in the payload.
Then, at runtime, clients send an _operation ID_ to run a persisted query. It looks like this in `params`:
@@ -116,4 +107,4 @@ params[:operationId] # => "relay-app-v1/810c97f6631001..."
## Getting Started
-See the {% internal_link "getting started guide","/operation_store/getting_started" %} to add `OperationStore` to your app.
+See the [getting started guide](/operation_store/getting_started) to add `OperationStore` to your app.
diff --git a/guides/operation_store/redis_backend.md b/guides/operation_store/redis_backend.md
index adc2fa590c5..1ba755fed08 100644
--- a/guides/operation_store/redis_backend.md
+++ b/guides/operation_store/redis_backend.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Redis Backend
-desc: Storing persisted queries with Redis
-index: 3
-pro: true
----
+# Redis Backend
`OperationStore` can use Redis to store persisted queries. Pass a `redis:` option when adding the plugin:
diff --git a/guides/operation_store/server_management.md b/guides/operation_store/server_management.md
index 7fe37854bc5..827f73a52ab 100644
--- a/guides/operation_store/server_management.md
+++ b/guides/operation_store/server_management.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro - OperationStore
-title: Server Management
-desc: Tips for administering persisted queries with OperationStore
-index: 5
-pro: true
----
-
-After {% internal_link "getting started","/operation_store/getting_started" %}, here some things to keep in mind.
+# Server Management
+
+After [getting started](/operation_store/getting_started), here some things to keep in mind.
## Rejecting Arbitrary Queries
@@ -55,7 +46,7 @@ MySchema.execute(
## Archiving and Deleting Data
-Clients can only _add_ to the database, but as an administrator, you can also archive or delete entries from the database. (Make sure you {% internal_link "authorize access to the Dashboard","/pro/dashboard" %}.) This is a dangerous operation: by archiving or deleting something, any clients who depend on that data will crash.
+Clients can only _add_ to the database, but as an administrator, you can also archive or delete entries from the database. (Make sure you [authorize access to the Dashboard](/pro/dashboard).) This is a dangerous operation: by archiving or deleting something, any clients who depend on that data will crash.
Some reasons to archive or delete from the database are:
@@ -74,4 +65,4 @@ It's on the road map to add a Ruby API to `OperationStore` so that you can integ
- Show client secrets via the Dashboard so that users can save them
- Render your own administration dashboards with `OperationStore` data
-If this interests you, please {% open_an_issue "OperationStore Ruby API" %} or email `support@graphql.pro`.
+If this interests you, please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=OperationStore+Ruby+API&body=) or email `support@graphql.pro`.
diff --git a/guides/pagination/connection_concepts.md b/guides/pagination/connection_concepts.md
index 74e77153ac6..684cd2cea2b 100644
--- a/guides/pagination/connection_concepts.md
+++ b/guides/pagination/connection_concepts.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Connection Concepts
-desc: Introduction to Connections
-index: 1
----
+# Connection Concepts
__Connections__ are a pagination solution which started with [Relay JS](https://facebook.github.io/relay), but now it's used for almost any GraphQL API.
@@ -52,7 +44,7 @@ Connections are often generated from object types. Their list items, called _nod
##### Connection metadata
-Connections can tell you about the list in general. For example, if you {% internal_link "add a total count field", "type_definitions/extensions#customizing-connections" %}, they can tell you the count:
+Connections can tell you about the list in general. For example, if you [add a total count field](/type_definitions/extensions#customizing-connections), they can tell you the count:
```ruby
{
diff --git a/guides/pagination/cursors.md b/guides/pagination/cursors.md
index 820ac0fd340..f8faa9abb6b 100644
--- a/guides/pagination/cursors.md
+++ b/guides/pagination/cursors.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Cursors
-desc: Advancing through lists with opaque cursors
-index: 4
----
+# Cursors
Connections use _cursors_ to advance through paginated lists. A cursor is an opaque string that indicates a specific point in this.
diff --git a/guides/pagination/custom_connections.md b/guides/pagination/custom_connections.md
index d10058b07c5..66860924574 100644
--- a/guides/pagination/custom_connections.md
+++ b/guides/pagination/custom_connections.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Custom Connections
-desc: Building & using cursor-based connections in GraphQL-Ruby
-index: 3
----
-
-GraphQL-Ruby ships with built-in connection support for ActiveRecord, Sequel, Mongoid, and Ruby Arrays. You can read more in the {% internal_link "Using Connections", "/pagination/using_connections" %} guide.
+# Custom Connections
+
+GraphQL-Ruby ships with built-in connection support for ActiveRecord, Sequel, Mongoid, and Ruby Arrays. You can read more in the [Using Connections](/pagination/using_connections) guide.
When you want to serve a connection based on your _own_ data object, you can create a custom connection. The implementation will have several components:
@@ -30,7 +22,7 @@ Your application probably has other list objects that you want to paginate via G
A connection wrapper is an adapter between a plain-Ruby list object (like an Array, Relation, or something application-specific, like `SearchEngine::Result`) and a GraphQL connection type. The connection wrapper implements methods which the GraphQL connection type requires, and it implements those methods based on the underlying list object.
-You can extend {{ "GraphQL::Pagination::Connection" | api_doc }} to get started on a custom connection wrapper, for example:
+You can extend [GraphQL::Pagination::Connection](rdoc-ref:GraphQL::Pagination::Connection) to get started on a custom connection wrapper, for example:
```ruby
# app/graphql/connections/search_results_connection.rb
@@ -48,10 +40,10 @@ The methods you must implement are:
How to implement these methods (efficiently!) depends on your backend and how you communicate with it. For inspiration, you can see the built-in connections:
-- {{ "GraphQL::Pagination::ArrayConnection" | api_doc }}
-- {{ "GraphQL::Pagination::ActiveRecordRelationConnection" | api_doc }}
-- {{ "GraphQL::Pagination::SequelDatasetConnection" | api_doc }}
-- {{ "GraphQL::Pagination::MongoidRelationConnection" | api_doc }}
+- [GraphQL::Pagination::ArrayConnection](rdoc-ref:GraphQL::Pagination::ArrayConnection)
+- [GraphQL::Pagination::ActiveRecordRelationConnection](rdoc-ref:GraphQL::Pagination::ActiveRecordRelationConnection)
+- [GraphQL::Pagination::SequelDatasetConnection](rdoc-ref:GraphQL::Pagination::SequelDatasetConnection)
+- [GraphQL::Pagination::MongoidRelationConnection](rdoc-ref:GraphQL::Pagination::MongoidRelationConnection)
### Using a Custom Connection
@@ -73,7 +65,7 @@ end
Now, any time a field returns an instance of `SearchEngine::Result`, it will be wrapped with `Connections::SearchResultsConnection`
-Alternatively, you can apply a connection wrapper on a case-by-case basis by applying it during the resolver (method or {{ "GraphQL::Schema::Resolver" | api_doc }}):
+Alternatively, you can apply a connection wrapper on a case-by-case basis by applying it during the resolver (method or [GraphQL::Schema::Resolver](rdoc-ref:GraphQL::Schema::Resolver)):
```ruby
field :search, Types::SearchResult.connection_type, null: false do
@@ -94,7 +86,7 @@ GraphQL-Ruby will use the provided connection wrapper in that case. You can use
Connection types are GraphQL object types which comply to the [Relay connection specification](https://relay.dev/graphql/connections.htm). GraphQL-Ruby ships with some tools to help you create those object types:
-- {{ "GraphQL::Types::Relay::BaseConnection" | api_doc }} and {{ "GraphQL::Types::Relay::BaseEdge" | api_doc }} are example implementations of the spec. They don't inherit from your application's base object class though, so you might not be able to use them out of the box.
+- [GraphQL::Types::Relay::BaseConnection](rdoc-ref:GraphQL::Types::Relay::BaseConnection) and [GraphQL::Types::Relay::BaseEdge](rdoc-ref:GraphQL::Types::Relay::BaseEdge) are example implementations of the spec. They don't inherit from your application's base object class though, so you might not be able to use them out of the box.
- Type classes respond to `.connection_type` which returns a generated connection type based on that class. By default, it inherits from the provided `GraphQL::Types::Relay::BaseConnection`, but you can override that by setting `connection_type_class(Types::MyBaseConnectionObject)` in your base classes.
For example, you could implement a base connection class:
diff --git a/guides/pagination/overview.md b/guides/pagination/overview.md
index 0828af92ed1..a5347c992df 100644
--- a/guides/pagination/overview.md
+++ b/guides/pagination/overview.md
@@ -1,16 +1,5 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Overview
-desc: Introduction to pagination in GraphQL
-index: 0
-redirect_from:
- - /relay/connections/
----
+# Overview
-
-GraphQL-Ruby ships with several implementations of Relay's "connection"-style pagination. You can familiarize yourself with connections in {% internal_link "Connection Concepts", "/pagination/connection_concepts" %} and see how to use them in {% internal_link "Using Connections", "/pagination/using_connections" %}. It also supports custom connection implementations and type definitions, which you can explore in the {% internal_link "Custom Connections", "/pagination/custom_connections" %} guide.
+GraphQL-Ruby ships with several implementations of Relay's "connection"-style pagination. You can familiarize yourself with connections in [Connection Concepts](/pagination/connection_concepts) and see how to use them in [Using Connections](/pagination/using_connections). It also supports custom connection implementations and type definitions, which you can explore in the [Custom Connections](/pagination/custom_connections) guide.
GraphQL has its own [great pagination docs](https://graphql.org/learn/pagination/) for further reading.
diff --git a/guides/pagination/stable_relation_connections.md b/guides/pagination/stable_relation_connections.md
index 3c20dafa285..2643c8ee838 100644
--- a/guides/pagination/stable_relation_connections.md
+++ b/guides/pagination/stable_relation_connections.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Stable Relation Connections
-desc: Advanced pagination for ActiveRecord
-index: 4
-pro: true
----
+# Stable Relation Connections
`GraphQL::Pro` includes a mechanism for serving _stable_ connections for `ActiveRecord::Relation`s based on column values. If objects are created or destroyed during pagination, the list of items won't be disrupted.
@@ -15,7 +6,7 @@ These connection implementations are database-specific so that they can build pr
## What's the difference?
-The default {{ "GraphQL::Pagination::ActiveRecordRelationConnection" | api_doc }} (which turns an `ActiveRecord::Relation` into a GraphQL-ready connection) uses _offset_ as a cursor. This naive approach is sufficient for many cases, but it's subject to a specific set of bugs.
+The default [GraphQL::Pagination::ActiveRecordRelationConnection](rdoc-ref:GraphQL::Pagination::ActiveRecordRelationConnection) (which turns an `ActiveRecord::Relation` into a GraphQL-ready connection) uses _offset_ as a cursor. This naive approach is sufficient for many cases, but it's subject to a specific set of bugs.
Let's say you're looking at the second page of 10 items (`LIMIT 10 OFFSET 10`). During that time, one of the items on page 1 is deleted. When you navigate to page 3 (`LIMIT 10 OFFSET 20`), you'll actually _miss_ one item. The entire list shifted "up" one position when a previous item was deleted.
diff --git a/guides/pagination/using_connections.md b/guides/pagination/using_connections.md
index 9bd9e722833..1cd9a04ba07 100644
--- a/guides/pagination/using_connections.md
+++ b/guides/pagination/using_connections.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Pagination
-title: Using Connections
-desc: Pagination with GraphQL-Ruby's built-in connections
-index: 2
----
-
-GraphQL-Ruby ships with a few implementations of the {% internal_link "connection pattern", "pagination/connection_concepts" %} that you can use out of the box. They support Ruby Arrays, Mongoid, Sequel, and ActiveRecord.
+# Using Connections
+
+GraphQL-Ruby ships with a few implementations of the [connection pattern](/pagination/connection_concepts) that you can use out of the box. They support Ruby Arrays, Mongoid, Sequel, and ActiveRecord.
Additionally, connections allow you to limit the number of items returned with [`max_page_size`](#max-page-size) and set the default number of items returned with [`default_page_size`](#default-page-size).
@@ -54,7 +46,7 @@ The collection object (Array, Mongoid relation, Sequel dataset, ActiveRecord rel
## Make Custom Connections
-If you want to paginate something that _isn't_ supported out-of-the-box, you can implement your own pagination wrapper and hook it up to GraphQL-Ruby. Read more in {% internal_link "Custom Connections", "/pagination/custom_connections" %}.
+If you want to paginate something that _isn't_ supported out-of-the-box, you can implement your own pagination wrapper and hook it up to GraphQL-Ruby. Read more in [Custom Connections](/pagination/custom_connections).
## Special Cases
diff --git a/guides/pro/dashboard.md b/guides/pro/dashboard.md
index 0b3fbf22bc5..26fc5d9e954 100644
--- a/guides/pro/dashboard.md
+++ b/guides/pro/dashboard.md
@@ -1,16 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro
-title: Dashboard
-desc: Installing GraphQL-Pro's Dashboard
-index: 4
-pro: true
----
-
-
-[GraphQL-Pro](https://graphql.pro) includes a web dashboard for monitoring {% internal_link "Operation Store", "/operation_store/overview" %} and {% internal_link "subscriptions", "/subscriptions/pusher_implementation" %}.
+# Dashboard
+
+[GraphQL-Pro](https://graphql.pro) includes a web dashboard for monitoring [Operation Store](/operation_store/overview) and [subscriptions](/subscriptions/pusher_implementation).
diff --git a/guides/pro/encoders.md b/guides/pro/encoders.md
index d2b7284b838..2b383f8071b 100644
--- a/guides/pro/encoders.md
+++ b/guides/pro/encoders.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro
-title: Encrypted, Versioned Cursors and IDs
-desc: Increased opacity and configurability for Relay identifiers
-index: 6
-pro: true
----
+# Encrypted, Versioned Cursors and IDs
`GraphQL::Pro` includes a mechanism for serving encrypted, versioned cursors and IDs. This provides some benefits:
@@ -47,7 +38,7 @@ end
Now, built-in connection implementations will use that encoder for cursors.
-If you implement your own connections, you can access the encoder's encryption methods via {{ "GraphQL::Pagination::Connection#encode" | api_doc }} and {{ "GraphQL::Pagination::Connection#decode" | api_doc }}.
+If you implement your own connections, you can access the encoder's encryption methods via `GraphQL::Pagination::Connection#encode` and `GraphQL::Pagination::Connection#decode`.
## Encrypting IDs
diff --git a/guides/pro/home.md b/guides/pro/home.md
index ad063c209cd..6101c794ad4 100644
--- a/guides/pro/home.md
+++ b/guides/pro/home.md
@@ -1,10 +1 @@
----
-layout: guide
-doc_stub: false
-outbound_url: https://graphql.pro
-title: GraphQL::Pro Home
-section: GraphQL Pro
-desc: Overview of GraphQL::Pro features
-index: 0
-pro: true
----
+# GraphQL::Pro Home
diff --git a/guides/pro/installation.md b/guides/pro/installation.md
index 2ae3fcdbe4a..cfeb1efdc74 100644
--- a/guides/pro/installation.md
+++ b/guides/pro/installation.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro
-title: Installation
-desc: Get started with GraphQL::Pro
-index: 1
-pro: true
----
+# Installation
`GraphQL::Pro` is distributed as a Ruby gem. When you buy `GraphQL::Pro`, you'll receive credentials, which you can register with bundler:
@@ -71,7 +62,7 @@ Validating graphql-pro v1.0.0
✔ graphql-pro 1.0.0 validated successfully!
```
-In case of a failure, please {% open_an_issue "GraphQL Pro installation failure" %}:
+In case of a failure, please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=GraphQL+Pro+installation+failure&body=):
```
Validating graphql-pro v1.4.800
diff --git a/guides/pro/privacy.md b/guides/pro/privacy.md
index c56f8d83657..8512a8f14cc 100644
--- a/guides/pro/privacy.md
+++ b/guides/pro/privacy.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: GraphQL Pro
-title: Privacy
-desc: Privacy Policy for GraphQL::Pro
-index: 7
----
+# Privacy
The following statement describes what data GraphQL::Pro collects during normal operation and how that data is used.
diff --git a/guides/queries/ast_analysis.md b/guides/queries/ast_analysis.md
index 2025774f1e2..0a12d0ccda5 100644
--- a/guides/queries/ast_analysis.md
+++ b/guides/queries/ast_analysis.md
@@ -1,18 +1,8 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-title: Ahead-of-Time AST Analysis
-desc: Check incoming query strings and reject them if they don't pass your checks
-index: 1
-redirect_from:
- - /queries/analysis/
----
+# Ahead-of-Time AST Analysis
You can do ahead-of-time analysis for your queries.
-The primitive for analysis is {{ "GraphQL::Analysis::Analyzer" | api_doc }}. Analyzers must inherit from this base class and implement the desired methods for analysis.
+The primitive for analysis is [GraphQL::Analysis::Analyzer](rdoc-ref:GraphQL::Analysis::Analyzer). Analyzers must inherit from this base class and implement the desired methods for analysis.
## Using Analyzers
@@ -32,7 +22,7 @@ Analyzers respond to methods similar to AST visitors. They're named like `on_ent
- `node`: The current AST node (being entered or left)
- `parent`: The AST node which precedes this one in the tree
-- `visitor`: A {{ "GraphQL::Analysis::Visitor" | api_doc }} which is managing this analysis run
+- `visitor`: A [GraphQL::Analysis::Visitor](rdoc-ref:GraphQL::Analysis::Visitor) which is managing this analysis run
For example:
@@ -85,15 +75,15 @@ class BasicFieldAnalyzer < GraphQL::Analysis::Analyzer
end
```
-See {{ "GraphQL::Analysis::Visitor" | api_doc }} for more information about the `visitor` object.
+See [GraphQL::Analysis::Visitor](rdoc-ref:GraphQL::Analysis::Visitor) for more information about the `visitor` object.
### Field Arguments
-Usually, analyzers will use `on_enter_field` and `on_leave_field` to process queries. To get a field's arguments during analysis, use `visitor.query.arguments_for(node, visitor.field_definition)` ({{ "GraphQL::Query#arguments_for" | api_doc }}). That method returns coerced argument values and normalizes argument literals and variable values.
+Usually, analyzers will use `on_enter_field` and `on_leave_field` to process queries. To get a field's arguments during analysis, use `visitor.query.arguments_for(node, visitor.field_definition)` ([GraphQL::Query#arguments_for](rdoc-ref:GraphQL::Query#arguments_for)). That method returns coerced argument values and normalizes argument literals and variable values.
### Errors
-It is still possible to return errors from an analyzer. To reject a query and halt its execution, you may return {{ "GraphQL::AnalysisError" | api_doc }} in the `result` method:
+It is still possible to return errors from an analyzer. To reject a query and halt its execution, you may return [GraphQL::AnalysisError](rdoc-ref:GraphQL::AnalysisError) in the `result` method:
```ruby
class NoFieldsCalledHello < GraphQL::Analysis::Analyzer
diff --git a/guides/queries/backtrace_annotations.md b/guides/queries/backtrace_annotations.md
index 4accf58194f..5eeb18032d5 100644
--- a/guides/queries/backtrace_annotations.md
+++ b/guides/queries/backtrace_annotations.md
@@ -1,13 +1,4 @@
----
-title: Backtrace Annotations
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Use the GraphQL backtrace for debugging
-index: 12
-experimental: true
----
+# Backtrace Annotations
`context` objects have a `backtrace` which shows its GraphQL context. You can print the backtrace during query execution:
diff --git a/guides/queries/complexity_and_depth.md b/guides/queries/complexity_and_depth.md
index b3294be8e82..5d9ff8a2496 100644
--- a/guides/queries/complexity_and_depth.md
+++ b/guides/queries/complexity_and_depth.md
@@ -1,14 +1,6 @@
----
-title: Complexity & Depth
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Limiting query depth and field selections
-index: 4
----
-
-GraphQL-Ruby ships with some validations based on {% internal_link "query analysis", "/queries/ast_analysis" %}. You can customize them as-needed, too.
+# Complexity & Depth
+
+GraphQL-Ruby ships with some validations based on [query analysis](/queries/ast_analysis). You can customize them as-needed, too.
## Prevent deeply-nested queries
@@ -34,7 +26,7 @@ You can use `nil` to disable the validation:
MySchema.execute(query_string, max_depth: nil)
```
-To get a feeling for depth of queries in your system, you can extend {{ "GraphQL::Analysis::QueryDepth" | api_doc }}. Hook it up to log out values from each query:
+To get a feeling for depth of queries in your system, you can extend [GraphQL::Analysis::QueryDepth](rdoc-ref:GraphQL::Analysis::QueryDepth). Hook it up to log out values from each query:
```ruby
class LogQueryDepth < GraphQL::Analysis::QueryDepth
@@ -100,7 +92,7 @@ Using `nil` will disable the validation:
MySchema.execute(query_string, max_complexity: nil)
```
-To get a feeling for complexity of queries in your system, you can extend {{ "GraphQL::Analysis::QueryComplexity" | api_doc }}. Hook it up to log out values from each query:
+To get a feeling for complexity of queries in your system, you can extend [GraphQL::Analysis::QueryComplexity](rdoc-ref:GraphQL::Analysis::QueryComplexity). Hook it up to log out values from each query:
```ruby
class LogQueryComplexityAnalyzer < GraphQL::Analysis::QueryComplexity
diff --git a/guides/queries/executing_queries.md b/guides/queries/executing_queries.md
index 5694afbb9dd..152d117b690 100644
--- a/guides/queries/executing_queries.md
+++ b/guides/queries/executing_queries.md
@@ -1,15 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-title: Executing Queries
-desc: Evaluate GraphQL queries with your schema
-index: 0
----
+# Executing Queries
-
-You can execute queries with your {{ "GraphQL::Schema" | api_doc }} and get a Ruby Hash as a result. For example, to execute a query from a string:
+You can execute queries with your [GraphQL::Schema](rdoc-ref:GraphQL::Schema) and get a Ruby Hash as a result. For example, to execute a query from a string:
```ruby
query_string = "{ ... }"
@@ -34,17 +25,16 @@ MySchema.multiplex([
# ]
```
-There are also several options you can use:
-
-- `variables:` provides values for `$`-named [query variables](https://graphql.org/learn/queries/#variables)
-- `context:` accepts application-specific data to pass to `resolve` functions
-- `root_value:` will be provided to root-level `resolve` functions as `obj`
-- `operation_name:` picks a [named operation](https://graphql.org/learn/queries/#operation-type-and-name) from the incoming string to execute
-- `document:` accepts an already-parsed query (instead of a string), see {{ "GraphQL.parse" | api_doc }}
-- `validate:` may be `false` to skip static validation for this query
-- `max_depth:` and `max_complexity:` may override schema-level values
+The complete option contract for `variables:`, `context:`, `root_value:`,
+`operation_name:`, `document:`, validation, and query limits is maintained in the
+[GraphQL::Query](rdoc-ref:GraphQL::Query) and
+[GraphQL::Schema](rdoc-ref:GraphQL::Schema) API references. The examples below
+focus on the application-level patterns built on those options.
-Some of these options are described in more detail below, see {{ "GraphQL::Query#initialize" | api_doc }} for more information.
+The API-specific portions of this page were migrated to the
+[GraphQL::Query](rdoc-ref:GraphQL::Query) and
+[GraphQL::Schema](rdoc-ref:GraphQL::Schema) source comments. This page keeps
+the variables, context, scoped-context, and root-value walkthroughs.
## Variables
@@ -65,7 +55,7 @@ variables = { "postId" => "1" }
MySchema.execute(query_string, variables: variables)
```
-If the variable is a {{ "GraphQL::Schema::InputObject" | api_doc }}, you can provide a nested hash, for example:
+If the variable is a [GraphQL::Schema::InputObject](rdoc-ref:GraphQL::Schema::InputObject), you can provide a nested hash, for example:
```ruby
query_string = "
@@ -121,7 +111,7 @@ def post(id:)
end
```
-Note that `context` is _not_ the hash that you passed it. It's an instance of {{ "GraphQL::Query::Context" | api_doc }}, but it delegates `#[]`, `#[]=`, and a few other methods to the hash you provide.
+Note that `context` is _not_ the hash that you passed it. It's an instance of [GraphQL::Query::Context](rdoc-ref:GraphQL::Query::Context), but it delegates `#[]`, `#[]=`, and a few other methods to the hash you provide.
### Scoped Context
@@ -143,16 +133,16 @@ However, "scoped context" can be used to assign values into `context` that are o
You could use "scoped context" to implement `isOriginalPoster`, based on the parent `comments` field.
-{% callout warning %}
-
-Using scoped context may result in a violation of [the GraphQL specification](https://spec.graphql.org/draft/#sel-EABDLDFAACHAo3V) and
-break normalized client stores, which assume that a given object always
-has the same values for its fields.
-
-See ["Referencing ancestors breaks normalized stores"](https://benjie.dev/graphql/ancestors#breaks-normalized-stores)
-for details about this pitfall and alternative approaches which avoid it.
+> **Warning:**
+>
+> Using scoped context may result in a violation of [the GraphQL specification](https://spec.graphql.org/draft/#sel-EABDLDFAACHAo3V) and
+> break normalized client stores, which assume that a given object always
+> has the same values for its fields.
+>
+> See ["Referencing ancestors breaks normalized stores"](https://benjie.dev/graphql/ancestors#breaks-normalized-stores)
+> for details about this pitfall and alternative approaches which avoid it.
+>
-{% endcallout %}
In `def comments`, add `:current_post` to scoped context using `context.scoped_set!`:
@@ -214,4 +204,4 @@ class Types::MutationType < GraphQL::Schema::Object
end
```
-{{ "GraphQL::Schema::Mutation" | api_doc }} fields will also receive `root_value:` as `obj` (assuming they're attached directly to your `MutationType`).
+[GraphQL::Schema::Mutation](rdoc-ref:GraphQL::Schema::Mutation) fields will also receive `root_value:` as `obj` (assuming they're attached directly to your `MutationType`).
diff --git a/guides/queries/logging.md b/guides/queries/logging.md
index f50fb61cfcb..7e1ecf88527 100644
--- a/guides/queries/logging.md
+++ b/guides/queries/logging.md
@@ -1,16 +1,8 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-title: Logging
-desc: Development output from GraphQL-Ruby
-index: 12
----
+# Logging
-At runtime, GraphQL-Ruby will output debug information using {{ "GraphQL::Query#logger" | api_doc }}. By default, this uses `Rails.logger`. To see output, make sure `config.log_level = :debug` is set. (This information isn't meant for production logs.)
+At runtime, GraphQL-Ruby will output debug information using [GraphQL::Query#logger](rdoc-ref:GraphQL::Query#logger). By default, this uses `Rails.logger`. To see output, make sure `config.log_level = :debug` is set. (This information isn't meant for production logs.)
-You can configure a custom logger with {{ "GraphQL::Schema.default_logger" | api_doc }}, for example:
+You can configure a custom logger with [GraphQL::Schema.default_logger](rdoc-ref:GraphQL::Schema.default_logger), for example:
```ruby
class MySchema < GraphQL::Schema
diff --git a/guides/queries/lookahead.md b/guides/queries/lookahead.md
index 8a5541d4851..f1ddc51cd13 100644
--- a/guides/queries/lookahead.md
+++ b/guides/queries/lookahead.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-title: Lookahead
-desc: Detecting child selections during field resolution
-index: 11
----
-
-GraphQL-Ruby 1.9+ includes {{ "GraphQL::Execution::Lookahead" | api_doc }} for checking whether child fields are selected. You can use this to optimize database access, for example, selecting only the _needed_ fields from the database.
+# Lookahead
+
+GraphQL-Ruby 1.9+ includes [GraphQL::Execution::Lookahead](rdoc-ref:GraphQL::Execution::Lookahead) for checking whether child fields are selected. You can use this to optimize database access, for example, selecting only the _needed_ fields from the database.
## Getting a Lookahead
diff --git a/guides/queries/multiplex.md b/guides/queries/multiplex.md
index 9e3d1301485..ef62d4a3f77 100644
--- a/guides/queries/multiplex.md
+++ b/guides/queries/multiplex.md
@@ -1,14 +1,6 @@
----
-title: Multiplex
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Run multiple queries concurrently
-index: 10
----
-
-Some clients may send _several_ queries to the server at once (for example, [Apollo Client's query batching](https://www.apollographql.com/docs/react/api/link/apollo-link-batch-http/)). You can execute them concurrently with {{ "Schema.multiplex" | api_doc }}.
+# Multiplex
+
+Some clients may send _several_ queries to the server at once (for example, [Apollo Client's query batching](https://www.apollographql.com/docs/react/api/link/apollo-link-batch-http/)). You can execute them concurrently with [Schema.multiplex](rdoc-ref:GraphQL::Schema.multiplex).
Multiplex runs have their own context, analyzers and instrumentation.
@@ -84,11 +76,11 @@ end
## Validation and Error Handling
-Each query is validated and {% internal_link "analyzed","/queries/ast_analysis" %} independently. The `results` array may include a mix of successful results and failed results.
+Each query is validated and [analyzed](/queries/ast_analysis) independently. The `results` array may include a mix of successful results and failed results.
## Multiplex-Level Context
-You can add values to {{ "Execution::Multiplex#context" | api_doc }} by providing a `context:` hash:
+You can add values to `Execution::Multiplex#context` by providing a `context:` hash:
```ruby
MySchema.multiplex(queries, context: { current_user: current_user })
@@ -107,15 +99,15 @@ class MySchema < GraphQL::Schema
end
```
-The API is the same as {% internal_link "query analyzers","/queries/ast_analysis#analyzing-multiplexes" %}.
+The API is the same as [query analyzers](/queries/ast_analysis#analyzing-multiplexes).
-Multiplex analyzers may return {{ "AnalysisError" | api_doc }} to halt execution of the whole multiplex.
+Multiplex analyzers may return [GraphQL::AnalysisError](rdoc-ref:GraphQL::AnalysisError) to halt execution of the whole multiplex.
## Multiplex Tracing
-You can add hooks for each multiplex run with {% internal_link "trace modules", "/queries/tracing" %}.
+You can add hooks for each multiplex run with [trace modules](/queries/tracing).
-The trace module may implement `def execute_multiplex(multiplex:)` which calls `super` to allow the multiplex to execute. See {{ "Execution::Multiplex" | api_doc }} for available methods.
+The trace module may implement `def execute_multiplex(multiplex:)` which calls `super` to allow the multiplex to execute. See `Execution::Multiplex` for available methods.
For example:
diff --git a/guides/queries/phases_of_execution.md b/guides/queries/phases_of_execution.md
index e75989a3ea0..d1fd6d8c75c 100644
--- a/guides/queries/phases_of_execution.md
+++ b/guides/queries/phases_of_execution.md
@@ -1,18 +1,10 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-title: Phases of Execution
-desc: The steps GraphQL takes to run your query
-index: 2
----
+# Phases of Execution
When GraphQL receives a query string, it goes through these steps:
-- Tokenize: {{ "GraphQL::Language::Lexer" | api_doc }} splits the string into a stream of tokens
-- Parse: {{ "GraphQL::Language::Parser" | api_doc }} builds an abstract syntax tree (AST) out of the stream of tokens
-- Validate: {{ "GraphQL::StaticValidation::Validator" | api_doc }} validates the incoming AST as a valid query for the schema
-- Analyze: If there are any query analyzers, they are run with {{ "GraphQL::Analysis.analyze_query" | api_doc }}
+- Tokenize: [GraphQL::Language::Lexer](rdoc-ref:GraphQL::Language::Lexer) splits the string into a stream of tokens
+- Parse: [GraphQL::Language::Parser](rdoc-ref:GraphQL::Language::Parser) builds an abstract syntax tree (AST) out of the stream of tokens
+- Validate: [GraphQL::StaticValidation::Validator](rdoc-ref:GraphQL::StaticValidation::Validator) validates the incoming AST as a valid query for the schema
+- Analyze: If there are any query analyzers, they are run with [GraphQL::Analysis.analyze_query](rdoc-ref:GraphQL::Analysis.analyze_query)
- Execute: The query is traversed, `resolve` functions are called and the response is built
-- Respond: The response is returned as a {{ "GraphQL::Query::Result" | api_doc }}
+- Respond: The response is returned as a [GraphQL::Query::Result](rdoc-ref:GraphQL::Query::Result)
diff --git a/guides/queries/response_extensions.md b/guides/queries/response_extensions.md
index 5602de450fe..f11ba2d6daa 100644
--- a/guides/queries/response_extensions.md
+++ b/guides/queries/response_extensions.md
@@ -1,12 +1,4 @@
----
-title: Response Extensions
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Adding "extensions" to the response hash
-index: 12
----
+# Response Extensions
During query execution, you can add to the response's `"extensions" => { ... }` Hash. By default, no `"extensions"` key is present in the result, but if you call the method below, it will be present with the given values.
diff --git a/guides/queries/timeout.md b/guides/queries/timeout.md
index d72c9a7d890..429f75b2b19 100644
--- a/guides/queries/timeout.md
+++ b/guides/queries/timeout.md
@@ -1,12 +1,4 @@
----
-title: Timeout
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Cutting off GraphQL execution
-index: 5
----
+# Timeout
You can apply a timeout to query execution with the `GraphQL::Schema::Timeout` plugin. For example:
@@ -38,7 +30,7 @@ end
## Customizing the Timeout Window
-To dynamically pick a timeout duration (or bypass it), override {{ "GraphQL::Schema::Timeout#max_seconds" | api_doc }} in your subclass. To bypass the timeout altogether, `max_seconds` can return `false`.
+To dynamically pick a timeout duration (or bypass it), override [GraphQL::Schema::Timeout#max_seconds](rdoc-ref:GraphQL::Schema::Timeout#max_seconds) in your subclass. To bypass the timeout altogether, `max_seconds` can return `false`.
For example:
diff --git a/guides/queries/tracing.md b/guides/queries/tracing.md
index 25612676bc9..9a7c2105863 100644
--- a/guides/queries/tracing.md
+++ b/guides/queries/tracing.md
@@ -1,16 +1,6 @@
----
-title: Tracing
-layout: guide
-doc_stub: false
-search: true
-section: Queries
-desc: Observation hooks for execution
-index: 11
-redirect_from:
- - /queries/instrumentation
----
-
-{{ "GraphQL::Tracing::Trace" | api_doc }} provides hooks to observe and modify events during runtime. Tracing hooks are methods, defined in modules and mixed in with {{ "Schema.trace_with" | api_doc }}.
+# Tracing
+
+[GraphQL::Tracing::Trace](rdoc-ref:GraphQL::Tracing::Trace) provides hooks to observe and modify events during runtime. Tracing hooks are methods, defined in modules and mixed in with [Schema.trace_with](rdoc-ref:GraphQL::Schema.trace_with).
```ruby
module CustomTrace
@@ -32,29 +22,29 @@ class MySchema < GraphQL::Schema
end
```
-For a full list of methods and their arguments, see {{ "GraphQL::Tracing::Trace" | api_doc }}.
+For a full list of methods and their arguments, see [GraphQL::Tracing::Trace](rdoc-ref:GraphQL::Tracing::Trace).
By default, GraphQL-Ruby makes a new trace instance when it runs a query. You can pass an existing instance as `context: { trace: ... }`. Also, `GraphQL.parse( ..., trace: ...)` accepts a trace instance.
## Detailed Traces
-You can capture detailed traces of query execution with {{ "Tracing::DetailedTrace" | api_doc }}. They can be viewed in Google's [Perfetto Trace Viewer](https://ui.perfetto.dev). They include a per-Fiber breakdown with links between fields and Dataloader sources.
+You can capture detailed traces of query execution with [Tracing::DetailedTrace](rdoc-ref:GraphQL::Tracing::DetailedTrace). They can be viewed in Google's [Perfetto Trace Viewer](https://ui.perfetto.dev). They include a per-Fiber breakdown with links between fields and Dataloader sources.
-{{ "/queries/perfetto_example.png" | link_to_img:"GraphQL-Ruby Dataloader Perfetto Trace" }}
+
-Learn how to set it up in the {{ "Tracing::DetailedTrace" | api_doc }} docs.
+Learn how to set it up in the [Tracing::DetailedTrace](rdoc-ref:GraphQL::Tracing::DetailedTrace) docs.
## External Monitoring Platforms
There integrations for GraphQL-Ruby with several other monitoring systems:
-- `ActiveSupport::Notifications`: See {{ "Tracing::ActiveSupportNotificationsTrace" | api_doc }}.
+- `ActiveSupport::Notifications`: See [Tracing::ActiveSupportNotificationsTrace](rdoc-ref:GraphQL::Tracing::ActiveSupportNotificationsTrace).
- [AppOptics](https://appoptics.com/) instrumentation is automatic in `appoptics_apm` v4.11.0+.
-- [AppSignal](https://appsignal.com/): See {{ "Tracing::AppsignalTrace" | api_doc }}.
-- [Datadog](https://www.datadoghq.com): See {{ "Tracing::DataDogTrace" | api_doc }}.
-- [NewRelic](https://newrelic.com/): See {{ "Tracing::NewRelicTrace" | api_doc }}.
-- [Prometheus](https://prometheus.io): See {{ "Tracing::PrometheusTrace" | api_doc }}.
-- [Scout APM](https://www.scoutapm.com/): See {{ "Tracing::ScoutTrace" | api_doc }}.
-- [Sentry](https://sentry.io): See {{ "Tracing::SentryTrace" | api_doc }}.
-- [Skylight](https://www.skylight.io): either enable the [GraphQL probe](https://www.skylight.io/support/getting-more-from-skylight#graphql) or use {{ "Tracing::ActiveSupportNotificationsTrace" | api_doc }}.
-- Statsd: See {{ "Tracing::StatsdTrace" | api_doc }}.
+- [AppSignal](https://appsignal.com/): See [Tracing::AppsignalTrace](rdoc-ref:GraphQL::Tracing::AppsignalTrace).
+- [Datadog](https://www.datadoghq.com): See [Tracing::DataDogTrace](rdoc-ref:GraphQL::Tracing::DataDogTrace).
+- [NewRelic](https://newrelic.com/): See [Tracing::NewRelicTrace](rdoc-ref:GraphQL::Tracing::NewRelicTrace).
+- [Prometheus](https://prometheus.io): See [Tracing::PrometheusTrace](rdoc-ref:GraphQL::Tracing::PrometheusTrace).
+- [Scout APM](https://www.scoutapm.com/): See [Tracing::ScoutTrace](rdoc-ref:GraphQL::Tracing::ScoutTrace).
+- [Sentry](https://sentry.io): See [Tracing::SentryTrace](rdoc-ref:GraphQL::Tracing::SentryTrace).
+- [Skylight](https://www.skylight.io): either enable the [GraphQL probe](https://www.skylight.io/support/getting-more-from-skylight#graphql) or use [Tracing::ActiveSupportNotificationsTrace](rdoc-ref:GraphQL::Tracing::ActiveSupportNotificationsTrace).
+- Statsd: See [Tracing::StatsdTrace](rdoc-ref:GraphQL::Tracing::StatsdTrace).
diff --git a/guides/related_projects.md b/guides/related_projects.md
index dff3e99c646..9d6cd464037 100644
--- a/guides/related_projects.md
+++ b/guides/related_projects.md
@@ -1,11 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Related Projects
-section: Other
-desc: Code, blog posts and presentations about GraphQL Ruby
----
+# Related Projects
Want to add something? Please open a pull request [on GitHub](https://github.com/rmosolgo/graphql-ruby)!
diff --git a/guides/relay/range_add.md b/guides/relay/range_add.md
index fd81f922e8d..6357f3b76d3 100644
--- a/guides/relay/range_add.md
+++ b/guides/relay/range_add.md
@@ -1,11 +1,3 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Relay
-title: RangeAdd helper for mutations
-desc: A helper for Relay's RANGE_ADD operations
-index: 1
----
+# RangeAdd helper for mutations
-Relay specifies `RANGE_ADD` operations for adding items to connections. GraphQL-Ruby ships with {{ "GraphQL::Relay::RangeAdd" | api_doc }} to help implement this. Check the API docs for a usage example.
+Relay specifies `RANGE_ADD` operations for adding items to connections. GraphQL-Ruby ships with [GraphQL::Relay::RangeAdd](rdoc-ref:GraphQL::Relay::RangeAdd) to help implement this. Check the API docs for a usage example.
diff --git a/guides/schema/definition.md b/guides/schema/definition.md
index d9038b3d3e7..401e3fb96d1 100644
--- a/guides/schema/definition.md
+++ b/guides/schema/definition.md
@@ -1,17 +1,8 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Schema
-title: Definition
-desc: Defining your schema
-index: 1
----
+# Definition
+A GraphQL system is called a _schema_. The schema contains all the types and fields in the system. The schema executes queries and publishes an [introspection system](/schema/introspection).
-A GraphQL system is called a _schema_. The schema contains all the types and fields in the system. The schema executes queries and publishes an {% internal_link "introspection system","/schema/introspection" %}.
-
-Your GraphQL schema is a class that extends {{ "GraphQL::Schema" | api_doc }}, for example:
+Your GraphQL schema is a class that extends [GraphQL::Schema](rdoc-ref:GraphQL::Schema), for example:
```ruby
class MyAppSchema < GraphQL::Schema
@@ -34,20 +25,30 @@ class MyAppSchema < GraphQL::Schema
end
```
-There are lots of schema configuration methods.
+There are lots of schema configuration methods. The complete reference is
+maintained with the implementation in [GraphQL::Schema](rdoc-ref:GraphQL::Schema),
+including root types, object identification, error hooks, limits, introspection,
+authorization, tracing, analyzers, and plugins.
+
+The API-specific portions of this page were migrated to the
+[GraphQL::Schema](rdoc-ref:GraphQL::Schema) source comments. This page keeps the
+setup, lazy-loading, and production walkthroughs.
-For defining GraphQL types, see the guides for those types: {% internal_link "object types", "/type_definitions/objects" %}, {% internal_link "interface types", "/type_definitions/interfaces" %}, {% internal_link "union types", "/type_definitions/unions" %}, {% internal_link "input object types", "/type_definitions/input_objects" %}, {% internal_link "enum types", "/type_definitions/enums" %}, and {% internal_link "scalar types", "/type_definitions/scalars" %}.
+For defining GraphQL types, see the guides for those types: [object types](/type_definitions/objects), [interface types](/type_definitions/interfaces), [union types](/type_definitions/unions), [input object types](/type_definitions/input_objects), [enum types](/type_definitions/enums), and [scalar types](/type_definitions/scalars).
## Types in the Schema
-- {{ "Schema.query" | api_doc }}, {{ "Schema.mutation" | api_doc }}, and {{ "Schema.subscription" | api_doc}} declare the [entry-point types](https://graphql.org/learn/schema/#the-query-mutation-and-subscription-types) of the schema.
-- {{ "Schema.orphan_types" | api_doc }} declares object types which implement {% internal_link "Interfaces", "/type_definitions/interfaces" %} but aren't used as field return types in the schema. For more about this specific scenario, see {% internal_link "Orphan Types", "/type_definitions/interfaces#orphan-types" %}
+See the [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema) for
+root types, orphan types, and extra types. For defining GraphQL types, see the
+guides for [object types](/type_definitions/objects), [interface types](/type_definitions/interfaces),
+[union types](/type_definitions/unions), [input objects](/type_definitions/input_objects),
+[enums](/type_definitions/enums), and [scalars](/type_definitions/scalars).
### Lazy-loading types
In development, GraphQL-Ruby can defer loading your type definitions until they're needed. This requires some configuration to opt in:
-- Add `use GraphQL::Schema::Visibility` to your schema. ({{ "GraphQL::Schema::Visibility" | api_doc }} supports lazy loading and will be the default in a future GraphQL-Ruby version. See {% internal_link "Migration Notes", "/authorization/visibility#migration-notes" %} if you have an existing visibility implementation.)
+- Add `use GraphQL::Schema::Visibility` to your schema. ([GraphQL::Schema::Visibility](rdoc-ref:GraphQL::Schema::Visibility) supports lazy loading and will be the default in a future GraphQL-Ruby version. See [Migration Notes](/authorization/visibility#migration-notes) if you have an existing visibility implementation.)
- Move your entry-point type definitions into a block, for example:
```diff
@@ -71,56 +72,54 @@ To enforce these patterns, you can enable two Rubocop rules that ship with Graph
## Object Identification
-Some GraphQL features use unique IDs to load objects:
-
-- the `node(id:)` field looks up objects by ID (See {% internal_link "Object Identification", "/schema/object_identification" %} for more about Relay-style object identification.)
-- any arguments with `loads:` configurations look up objects by ID
-- the {% internal_link "ObjectCache", "/object_cache/overview" %} uses IDs in its caching scheme
-
-To use these features, you must provide some methods for generating UUIDs and fetching objects with them:
-
-{{ "Schema.object_from_id" | api_doc }} is called by GraphQL-Ruby to load objects directly from the database. It's usually used by the `node(id: ID!): Node` field (see {{ "GraphQL::Types::Relay::Node" | api_doc }}), Argument {% internal_link "loads:", "/mutations/mutation_classes#auto-loading-arguments" %}, or the {% internal_link "ObjectCache", "/object_cache/overview" %}. It receives a unique ID and must return the object for that ID, or `nil` if the object isn't found (or if it should be hidden from the current user).
-
-{{ "Schema.id_from_object" | api_doc }} is used to implement `Node.id`. It should return a unique ID for the given object. This ID will later be sent to `object_from_id` to refetch the object.
-
-Additionally, {{ "Schema.resolve_type" | api_doc }} is called by GraphQL-Ruby to get the runtime Object type for fields that return {% internal_link "interface", "/type_definitions/interfaces" %} or {% internal_link "union", "/type_definitions/unions" %} types.
+The [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+documents `object_from_id`, `id_from_object`, and `resolve_type`. For Relay-style
+IDs, see [Object Identification](/schema/object_identification); for `loads:`, see
+[auto-loading arguments](/mutations/mutation_classes#auto-loading-arguments).
## Error Handling
-- {{ "Schema.type_error" | api_doc }} handles type errors at runtime, read more in the {% internal_link "Type errors guide", "/errors/type_errors" %}.
-- {{ "Schema.rescue_from" | api_doc }} defines error handlers for application errors. See the {% internal_link "error handling guide", "/errors/error_handling" %} for more.
-- {{ "Schema.parse_error" | api_doc }} and {{ "Schema.query_stack_error" | api_doc }} provide hooks for reporting errors to your bug tracker.
+The [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+describes the error hooks. See the [Type errors guide](/errors/type_errors) and
+[error handling guide](/errors/error_handling) for application-level examples.
## Default Limits
-- {{ "Schema.max_depth" | api_doc }} and {{ "Schema.max_complexity" | api_doc }} apply some limits to incoming queries. See {% internal_link "Complexity and Depth", "/queries/complexity_and_depth" %} for more.
-- {{ "Schema.default_max_page_size" | api_doc }} applies limits to {% internal_link "connection fields", "/pagination/overview" %}.
-- {{ "Schema.validate_timeout" | api_doc }}, {{ "Schema.validate_max_errors" | api_doc }} and {{ "Schema.max_query_string_tokens" | api_doc }} all apply limits to query execution. See {% internal_link "Timeout", "/queries/timeout" %} for more.
+See the [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+for depth, complexity, page-size, timeout, error-count, and query-token limits.
+The [Complexity and Depth](/queries/complexity_and_depth) and [Timeout](/queries/timeout)
+guides show deployment-oriented examples.
## Introspection
-- {{ "Schema.extra_types" | api_doc }} declares types which should be printed in the SDL and returned in introspection queries, but aren't otherwise used in the schema.
-- {{ "Schema.introspection" | api_doc }} can attach a {% internal_link "custom introspection system", "/schema/introspection" %} to the schema.
+The [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+documents `extra_types` and custom introspection namespaces. See the
+[introspection guide](/schema/introspection) for a custom introspection system.
## Authorization
-- {{ "Schema.unauthorized_object" | api_doc }} and {{ "Schema.unauthorized_field" | api_doc }} are called when {% internal_link "authorization hooks", "/authorization/authorization" %} return `false` during query execution.
+The [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+documents the unauthorized object and field hooks. See the
+[authorization guide](/authorization/authorization) for the complete authorization flow.
## Execution Configuration
-- {{ "Schema.trace_with" | api_doc }} attaches tracer modules. See {% internal_link "Tracing", "/queries/tracing" %} for more.
-- {{ "Schema.query_analyzer" | api_doc }} and {{ "Schema.multiplex_analyzer" }} accept processors for ahead-of-time query analysis, see {% internal_link "Analysis", "/queries/ast_analysis" %} for more.
-- {{ "Schema.default_logger" | api_doc }} configures a logger for runtime. See {% internal_link "Logging", "/queries/logging" %}.
-- {{ "Schema.context_class" | api_doc }} and {{ "Schema.query_class" | api_doc }} attach custom subclasses to your schema to use during execution.
-- {{ "Schema.lazy_resolve" | api_doc }} registers classes with {% internal_link "lazy execution", "/schema/lazy_execution" %}.
+The [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema)
+documents tracing, analyzers, logging, custom execution classes, lazy values, and
+plugins. See [Tracing](/queries/tracing), [Analysis](/queries/ast_analysis),
+[Logging](/queries/logging), and [lazy execution](/schema/lazy_execution) for
+cross-cutting examples.
## Plugins
-- {{ "Schema.use" | api_doc }} adds plugins to your schema. For example, {{ "GraphQL::Dataloader" | api_doc }} and {{ "GraphQL::Schema::Visibility" | api_doc }} are installed this way.
+Use [Schema.use](rdoc-ref:GraphQL::Schema.use) to install plugins such as
+[GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) and
+[GraphQL::Schema::Visibility](rdoc-ref:GraphQL::Schema::Visibility). The plugin
+contract is documented in the [GraphQL::Schema API reference](rdoc-ref:GraphQL::Schema).
## Production Considerations
-- __Parser caching__: if your application parses GraphQL _files_ (queries or schema definition), it may benefit from enabling {{ "GraphQL::Language::Cache" | api_doc }}.
+- __Parser caching__: if your application parses GraphQL _files_ (queries or schema definition), it may benefit from enabling [GraphQL::Language::Cache](rdoc-ref:GraphQL::Language::Cache).
- __Eager loading the library__: by default, GraphQL-Ruby autoloads its constants as-needed. In production, they should be eager loaded instead, using `GraphQL.eager_load!`.
- Rails: enabled automatically. (ActiveSupport calls `.eager_load!`.)
@@ -128,4 +127,4 @@ Additionally, {{ "Schema.resolve_type" | api_doc }} is called by GraphQL-Ruby to
- Hanami: add `environment(:production) { GraphQL.eager_load! }` to your application file.
- Other frameworks: call `GraphQL.eager_load!` when your application is booting in production mode.
- See {{"GraphQL::Autoload#eager_load!" | api_doc }} for more details.
+ See [GraphQL::Autoload#eager_load!](rdoc-ref:GraphQL::Autoload#eager_load!) for more details.
diff --git a/guides/schema/dynamic_types.md b/guides/schema/dynamic_types.md
index 9497b5d2e86..6bc0cbef9e3 100644
--- a/guides/schema/dynamic_types.md
+++ b/guides/schema/dynamic_types.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Schema
-title: Dynamic types and fields
-desc: Using different schema members for each request
-index: 8
----
+# Dynamic types and fields
You can use different versions of your GraphQL schema for each operation. To do this, add `use GraphQL::Schema::Visibility` and implement `visible?(context)` on the parts of your schema that will be conditionally accessible. Additionally, many schema elements have definition methods which are called at runtime by GraphQL-Ruby. You can re-implement those to return any valid schema objects.
@@ -23,7 +15,7 @@ You can customize which field definitions are used for each operation.
### Using `#visible?(context)`
-To serve different fields to different clients, implement `def visible?(context)` in your {% internal_link "base field class", "/type_definitions/extensions#customizing-fields" %}:
+To serve different fields to different clients, implement `def visible?(context)` in your [base field class](/type_definitions/extensions#customizing-fields):
```ruby
class Types::BaseField < GraphQL::Schema::Field
@@ -98,7 +90,7 @@ As with fields, you can use different sets of argument definitions for different
### Using `#visible?(context)`
-To serve different arguments to different clients, implement `def visible?(context)` in your {% internal_link "base argument class", "/type_definitions/extensions#customizing-arguments" %}:
+To serve different arguments to different clients, implement `def visible?(context)` in your [base argument class](/type_definitions/extensions#customizing-arguments):
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
@@ -140,7 +132,7 @@ That way, any staff client will have the option of `id` or `databaseId` while no
### Using `def arguments(context)` and `def get_argument(name, context)`
-Also, you can implement `def arguments(context)` on your base field class to return a Hash of `{ String => GraphQL::Schema::Argument }` and `def get_argument(name, context)` to return a {{ "GraphQL::Schema::Argument" | api_doc }} or `nil`. . If you take this approach, you might want some custom field classes for any types or resolvers that use these methods. That way, you don't have to reimplement the method for _all_ the fields in the schema.
+Also, you can implement `def arguments(context)` on your base field class to return a Hash of `{ String => GraphQL::Schema::Argument }` and `def get_argument(name, context)` to return a [GraphQL::Schema::Argument](rdoc-ref:GraphQL::Schema::Argument) or `nil`. . If you take this approach, you might want some custom field classes for any types or resolvers that use these methods. That way, you don't have to reimplement the method for _all_ the fields in the schema.
### Hidden Input Types
@@ -150,7 +142,7 @@ Besides argument visibility described above, if an argument's input type is hidd
### Using `#visible?(context)`
-You can implement `def visible?(context)` in your {% internal_link "base enum value class", "/type_definitions/extensions#customizing-enum-values" %} to hide some enum values from some clients. For example:
+You can implement `def visible?(context)` in your [base enum value class](/type_definitions/extensions#customizing-enum-values) to hide some enum values from some clients. For example:
```ruby
class BaseEnumValue < GraphQL::Schema::EnumValue
@@ -189,7 +181,7 @@ end
### Using `.enum_values(context)`
-Alternatively, you can implement `def self.enum_values(context)` in your enum types to return an Array of {{ "GraphQL::Schema::EnumValue" | api_doc }}s. For example, to return a dynamic set of enum values:
+Alternatively, you can implement `def self.enum_values(context)` in your enum types to return an Array of [GraphQL::Schema::EnumValue](rdoc-ref:GraphQL::Schema::EnumValue)s. For example, to return a dynamic set of enum values:
```ruby
class ProjectStatus < Types::BaseEnum
@@ -297,7 +289,7 @@ Input types (like input objects, scalars, and enums) work the same way with argu
## Schema Dumps
-To dump a certain _version_ of the schema, provide the applicable `context: ...` to {{ "Schema.to_definition" | api_doc }}. For example:
+To dump a certain _version_ of the schema, provide the applicable `context: ...` to [Schema.to_definition](rdoc-ref:GraphQL::Schema.to_definition). For example:
```ruby
# Legacy money schema:
diff --git a/guides/schema/generators.md b/guides/schema/generators.md
index 433d8ca3bad..2ec5cac40f9 100644
--- a/guides/schema/generators.md
+++ b/guides/schema/generators.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Generators
-section: Schema
-desc: Use Rails generators to install GraphQL and scaffold new types.
-index: 3
----
+# Generators
If you're using GraphQL with Ruby on Rails, you can use generators to:
@@ -33,7 +25,7 @@ This will:
- Add a `Mutation` type definition with a base mutation class
- Add a route and controller for executing queries
- Install [`graphiql-rails`](https://github.com/rmosolgo/graphiql-rails)
-- Enable [`ActiveRecord::QueryLogs`](https://api.rubyonrails.org/classes/ActiveRecord/QueryLogs.html) and add GraphQL-related metadata (using {{ "GraphQL::Current" | api_doc }})
+- Enable [`ActiveRecord::QueryLogs`](https://api.rubyonrails.org/classes/ActiveRecord/QueryLogs.html) and add GraphQL-related metadata (using [GraphQL::Current](rdoc-ref:GraphQL::Current))
After installing you can see your new schema by:
diff --git a/guides/schema/introspection.md b/guides/schema/introspection.md
index 688086823ae..97d0eb5e9fb 100644
--- a/guides/schema/introspection.md
+++ b/guides/schema/introspection.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Introspection
-section: Schema
-desc: GraphQL has an introspection system that tells about the schema.
-index: 3
----
+# Introspection
A GraphQL schema has a [built-in introspection system](https://graphql.org/learn/introspection/) that publishes the schema's structure. In fact, the introspection system can be queried using GraphQL, for example:
@@ -111,9 +103,9 @@ Keep in mind that off-the-shelf tooling may not support your custom introspectio
The introspection namespace may contain a few different customizations:
-- Class-based {% internal_link "object definitions", "/type_definitions/objects" %} which replace the built-in introspection types (such as `__Schema` and `__Type`)
-- `EntryPoints`, A class-based {% internal_link "object definition", "/type_definitions/objects" %} containing introspection entry points (like `__schema` and `__type(name:)`).
-- `DynamicFields`, A class-based {% internal_link "object definition", "/type_definitions/objects" %} containing dynamic, globally-available fields (like `__typename`.)
+- Class-based [object definitions](/type_definitions/objects) which replace the built-in introspection types (such as `__Schema` and `__Type`)
+- `EntryPoints`, A class-based [object definition](/type_definitions/objects) containing introspection entry points (like `__schema` and `__type(name:)`).
+- `DynamicFields`, A class-based [object definition](/type_definitions/objects) containing dynamic, globally-available fields (like `__typename`.)
### Custom Introspection Types
@@ -121,14 +113,14 @@ The `module` passed as `introspection` may contain classes with the following na
Custom class name | GraphQL type | Built-in class name
--|--|--
-`SchemaType` | `__Schema` | {{ "GraphQL::Introspection::SchemaType" | api_doc }}
-`TypeType` | `__Type` | {{ "GraphQL::Introspection::TypeType" | api_doc }}
-`DirectiveType` | `__Directive` | {{ "GraphQL::Introspection::DirectiveType" | api_doc }}
-`DirectiveLocationType` | `__DirectiveLocation` | {{ "GraphQL::Introspection::DirectiveLocationEnum" | api_doc }}
-`EnumValueType` | `__EnumValue` | {{ "GraphQL::Introspection::EnumValueType" | api_doc }}
-`FieldType` | `__Field` | {{ "GraphQL::Introspection::FieldType" | api_doc }}
-`InputValueType` | `__InputValue` | {{ "GraphQL::Introspection::InputValueType" | api_doc }}
-`TypeKindType` | `__TypeKind` | {{ "GraphQL::Introspection::TypeKindEnum" | api_doc }}
+`SchemaType` | `__Schema` | [GraphQL::Introspection::SchemaType](rdoc-ref:GraphQL::Introspection::SchemaType)
+`TypeType` | `__Type` | [GraphQL::Introspection::TypeType](rdoc-ref:GraphQL::Introspection::TypeType)
+`DirectiveType` | `__Directive` | [GraphQL::Introspection::DirectiveType](rdoc-ref:GraphQL::Introspection::DirectiveType)
+`DirectiveLocationType` | `__DirectiveLocation` | [GraphQL::Introspection::DirectiveLocationEnum](rdoc-ref:GraphQL::Introspection::DirectiveLocationEnum)
+`EnumValueType` | `__EnumValue` | [GraphQL::Introspection::EnumValueType](rdoc-ref:GraphQL::Introspection::EnumValueType)
+`FieldType` | `__Field` | [GraphQL::Introspection::FieldType](rdoc-ref:GraphQL::Introspection::FieldType)
+`InputValueType` | `__InputValue` | [GraphQL::Introspection::InputValueType](rdoc-ref:GraphQL::Introspection::InputValueType)
+`TypeKindType` | `__TypeKind` | [GraphQL::Introspection::TypeKindEnum](rdoc-ref:GraphQL::Introspection::TypeKindEnum)
The class-based definitions' names _must_ match the names of the types they replace.
diff --git a/guides/schema/lazy_execution.md b/guides/schema/lazy_execution.md
index 2e5cdaad421..fa3014161c9 100644
--- a/guides/schema/lazy_execution.md
+++ b/guides/schema/lazy_execution.md
@@ -1,17 +1,9 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Lazy Execution
-section: Schema
-desc: Resolvers can return "unfinished" results that are deferred for batch resolution.
-index: 4
----
+# Lazy Execution
With lazy execution, you can optimize access to external services (such as databases) by making batched calls. Building a lazy loader has three steps:
- Define a lazy-loading class with _one_ method for loading & returning a value
-- Connect it to your schema with {{ "GraphQL::Schema.lazy_resolve" | api_doc }}
+- Connect it to your schema with [GraphQL::Schema.lazy_resolve](rdoc-ref:GraphQL::Schema.lazy_resolve)
- In `resolve` methods, return instances of the lazy-loading class
## Example: Batched Find
@@ -90,7 +82,7 @@ Will only make one query to load the `author` values.
The example above is simple and has some shortcomings. Consider the following gems for a robust solution to batched resolution:
-* {{ "GraphQL::Dataloader" | api_doc }} is a built-in, Fiber-based approach to batching. See the {% internal_link "Dataloader guide", "/dataloader/overview" %} for more information.
+* [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) is a built-in, Fiber-based approach to batching. See the [Dataloader guide](/dataloader/overview) for more information.
* [`graphql-batch`](https://github.com/shopify/graphql-batch) provides a powerful, flexible toolkit for lazy resolution with GraphQL.
* [`dataloader`](https://github.com/sheerun/dataloader) is more general promise-based utility for batching queries within the same thread.
* [`batch-loader`](https://github.com/exAspArk/batch-loader) works with any Ruby code including GraphQL, no extra dependencies or primitives.
diff --git a/guides/schema/object_identification.md b/guides/schema/object_identification.md
index 9ae80c4d8d1..274d98fd4eb 100644
--- a/guides/schema/object_identification.md
+++ b/guides/schema/object_identification.md
@@ -1,24 +1,16 @@
----
-layout: guide
-doc_stub: false
-search: true
-title: Object Identification
-section: Schema
-desc: Working with unique global IDs
-index: 8
----
+# Object Identification
GraphQL-Ruby ships with some helpers to implement [Relay-style object identification](https://relay.dev/graphql/objectidentification.htm).
## Schema methods
-See {% internal_link "the Schema definition guide", "/schema/definition#object-identification" %} for required top-level hooks.
+See [the Schema definition guide](/schema/definition#object-identification) for required top-level hooks.
## Node interface
One requirement for Relay's object management is implementing the `"Node"` interface.
-To implement the node interface, add {{ "GraphQL::Types::Relay::Node" | api_doc }} to your definition:
+To implement the node interface, add [GraphQL::Types::Relay::Node](rdoc-ref:GraphQL::Types::Relay::Node) to your definition:
```ruby
class Types::PostType < GraphQL::Schema::Object
@@ -51,7 +43,7 @@ end
Nodes must have a field named `"id"` which returns a globally unique ID.
-To add a UUID field named `"id"`, implement the {{ "GraphQL::Types::Relay::Node" | api_doc }} interface::
+To add a UUID field named `"id"`, implement the [GraphQL::Types::Relay::Node](rdoc-ref:GraphQL::Types::Relay::Node) interface::
```ruby
class Types::PostType < GraphQL::Schema::Object
diff --git a/guides/schema/root_types.md b/guides/schema/root_types.md
index c0bb1df703e..6b90818d0dd 100644
--- a/guides/schema/root_types.md
+++ b/guides/schema/root_types.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Schema
-title: Root Types
-desc: Root types are the entry points for queries, mutations and subscriptions.
-index: 2
----
+# Root Types
GraphQL queries begin from [root types](https://graphql.org/learn/schema/#the-query-mutation-and-subscription-types): `query`, `mutation`, and `subscription`.
diff --git a/guides/schema/sdl.md b/guides/schema/sdl.md
index db2884cf9b0..df7ed77754c 100644
--- a/guides/schema/sdl.md
+++ b/guides/schema/sdl.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Schema
-title: Parsing GraphQL Schema Definition Language into a Ruby Schema
-desc: Defining a schema from a string or .graphql file
-index: 7
----
-
-GraphQL-Ruby includes a way to build a runable schema from the GraphQL Schema Definition Language (SDL). {{ "GraphQL::Schema.from_definition" | api_doc }} returns a schema class based on a filename or string containing GraphQL SDL. For example:
+# Parsing GraphQL Schema Definition Language into a Ruby Schema
+
+GraphQL-Ruby includes a way to build a runable schema from the GraphQL Schema Definition Language (SDL). [GraphQL::Schema.from_definition](rdoc-ref:GraphQL::Schema.from_definition) returns a schema class based on a filename or string containing GraphQL SDL. For example:
```ruby
# From a file:
@@ -78,7 +70,7 @@ The hash may contain:
## Plugins
-{{ "GraphQL::Schema.from_definition" | api_doc }} accepts a `using:` argument, which may be given as a map of `plugin => args` pairs. For example:
+[GraphQL::Schema.from_definition](rdoc-ref:GraphQL::Schema.from_definition) accepts a `using:` argument, which may be given as a map of `plugin => args` pairs. For example:
```ruby
MySchema = GraphQL::Schema.from_definition("path/to/schema.graphql", using: {
@@ -104,4 +96,4 @@ pp schema.get_field("Query", "secret").ast_node.directives.map(&:to_query_string
# => ["@privacy(secret: true)"]
```
-See {{ "GraphQL::Language::Nodes::Directive" | api_doc }} for available methods.
+See [GraphQL::Language::Nodes::Directive](rdoc-ref:GraphQL::Language::Nodes::Directive) for available methods.
diff --git a/guides/subscriptions/ably_implementation.md b/guides/subscriptions/ably_implementation.md
index faeeea0e153..9abcdc4f6e5 100644
--- a/guides/subscriptions/ably_implementation.md
+++ b/guides/subscriptions/ably_implementation.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Ably Implementation
-desc: GraphQL subscriptions over Ably
-index: 7
-pro: true
----
+# Ably Implementation
[GraphQL Pro](https://graphql.pro) includes a subscription system based on [Redis](https://redis.io) and [Ably](https://ably.io) which works with any Ruby web framework.
@@ -130,7 +121,7 @@ For better performance reading and writing to Redis, you can pass a `connection_
### Broadcasts
-If you set up {% internal_link "Broadcasts", "/subscriptions/broadcast" %}, then you can update many clients over a single Ably channel.
+If you set up [Broadcasts](/subscriptions/broadcast), then you can update many clients over a single Ably channel.
Broadcast channels have stable, predictable IDs. To prevent unauthorized clients from "listening in," use [token authorization](#authorization) for transport. Broadcasts channels use the namespace `gqlbdcst:`, so you can provide capabilities to receive them using `"gqlbdcst:*" => [ ... ]` in your authorization code. (If you're using [encryption](#encryption), the prefix will be `ablyencr-gqlbdcst:` instead.)
@@ -266,7 +257,7 @@ __Backwards compatibility:__ `GraphQL::Pro::AblySubscriptions` will only encrypt
Since subscription state is stored in the database, then reloaded for pushing updates, you have to serialize and reload your query `context`.
-By default, this is done with {{ "GraphQL::Subscriptions::Serialize" | api_doc }}'s `dump` and `load` methods, but you can provide custom implementations as well. To customize the serialization logic, create a subclass of `GraphQL::Pro::AblySubscriptions` and override `#dump_context(ctx)` and `#load_context(ctx_string)`:
+By default, this is done with `GraphQL::Subscriptions::Serialize`'s `dump` and `load` methods, but you can provide custom implementations as well. To customize the serialization logic, create a subclass of `GraphQL::Pro::AblySubscriptions` and override `#dump_context(ctx)` and `#load_context(ctx_string)`:
```ruby
class CustomSubscriptions < GraphQL::Pro::AblySubscriptions
@@ -296,17 +287,17 @@ That gives you fine-grained control of context reloading.
## Dashboard
-You can monitor subscription state in the {% internal_link "GraphQL-Pro Dashboard", "/pro/dashboard" %}:
+You can monitor subscription state in the [GraphQL-Pro Dashboard](/pro/dashboard):
-{{ "/subscriptions/redis_dashboard_1.png" | link_to_img:"Redis Subscription Dashboard" }}
+
-{{ "/subscriptions/redis_dashboard_2.png" | link_to_img:"Redis Subscription Detail" }}
+
## Development Tips
#### Clear subscription data
-At any time, you can reset your subscription database with the __"Reset"__ button in the {% internal_link "GraphQL-Pro Dashboard", "/pro/dashboard" %}, or in Ruby:
+At any time, you can reset your subscription database with the __"Reset"__ button in the [GraphQL-Pro Dashboard](/pro/dashboard), or in Ruby:
```ruby
# Wipe all subscription data from the DB:
@@ -321,6 +312,6 @@ To receive webhooks in development, you can [use ngrok](https://www.ably.io/tuto
Install the [Ably JS client](https://github.com/ably/ably-js) then see docs for:
-- {% internal_link "Apollo Client", "/javascript_client/apollo_subscriptions" %}
-- {% internal_link "Relay Modern", "/javascript_client/relay_subscriptions" %}.
-- {% internal_link "GraphiQL", "/javascript_client/graphiql_subscriptions" %}
+- [Apollo Client](/javascript_client/apollo_subscriptions)
+- [Relay Modern](/javascript_client/relay_subscriptions).
+- [GraphiQL](/javascript_client/graphiql_subscriptions)
diff --git a/guides/subscriptions/action_cable_implementation.md b/guides/subscriptions/action_cable_implementation.md
index 6969c45c4bc..c1d00543089 100644
--- a/guides/subscriptions/action_cable_implementation.md
+++ b/guides/subscriptions/action_cable_implementation.md
@@ -1,19 +1,11 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Action Cable Implementation
-desc: GraphQL subscriptions over ActionCable
-index: 4
----
+# Action Cable Implementation
[ActionCable](https://guides.rubyonrails.org/action_cable_overview.html) is a great platform for delivering GraphQL subscriptions on Rails 5+. It handles message passing (via `broadcast`) and transport (via `transmit` over a websocket).
-To get started, see examples in the API docs: {{ "GraphQL::Subscriptions::ActionCableSubscriptions" | api_doc }}. GraphQL-Ruby also includes a mock ActionCable implementation for testing: {{ "GraphQL::Testing::MockActionCable" | api_doc }}.
+To get started, see examples in the API docs: [GraphQL::Subscriptions::ActionCableSubscriptions](rdoc-ref:GraphQL::Subscriptions::ActionCableSubscriptions). GraphQL-Ruby also includes a mock ActionCable implementation for testing: [GraphQL::Testing::MockActionCable](rdoc-ref:GraphQL::Testing::MockActionCable).
See client usage for:
-- {% internal_link "Apollo Client", "/javascript_client/apollo_subscriptions" %}
-- {% internal_link "Relay Modern", "/javascript_client/relay_subscriptions" %}.
-- {% internal_link "GraphiQL", "/javascript_client/graphiql_subscriptions" %}
+- [Apollo Client](/javascript_client/apollo_subscriptions)
+- [Relay Modern](/javascript_client/relay_subscriptions).
+- [GraphiQL](/javascript_client/graphiql_subscriptions)
diff --git a/guides/subscriptions/broadcast.md b/guides/subscriptions/broadcast.md
index 9614fe8e590..5e486bfda2d 100644
--- a/guides/subscriptions/broadcast.md
+++ b/guides/subscriptions/broadcast.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Broadcasts
-desc: Delivering the same GraphQL result to multiple subscribers
-index: 3
----
+# Broadcasts
GraphQL subscription updates may _broadcast_ data to multiple subscribers.
@@ -79,13 +71,13 @@ GraphQL-Ruby determines which subscribers can receive a broadcast by inspecting:
- __Field and Arguments__ given to `.trigger`. They must match the ones initially sent when subscribing. (Subscriptions always worked this way.)
- __Subscription scope__. Only clients with exactly-matching subscription scope can receive the same broadcasts.
-So, take care to {% internal_link "set subscription_scope", "subscriptions/subscription_classes#scope" %} whenever a subscription should be implicitly scoped!
+So, take care to [set subscription_scope](/subscriptions/subscription_classes#scope) whenever a subscription should be implicitly scoped!
-(See {{ "GraphQL::Subscriptions::Event#fingerprint" | api_doc }} for the implementation of broadcast fingerprints.)
+(See [GraphQL::Subscriptions::Event#fingerprint](rdoc-ref:GraphQL::Subscriptions::Event#fingerprint) for the implementation of broadcast fingerprints.)
## Checking for Broadcastable
-For testing purposes, you can confirm that a GraphQL query string is broadcastable by using {{ "Subscriptions#broadcastable?" | api_doc }}:
+For testing purposes, you can confirm that a GraphQL query string is broadcastable by using [Subscriptions#broadcastable?](rdoc-ref:GraphQL::Subscriptions#broadcastable?):
```ruby
subscription_string = "subscription { ... }"
diff --git a/guides/subscriptions/implementation.md b/guides/subscriptions/implementation.md
index c34336c2aa5..2b0e3a5451b 100644
--- a/guides/subscriptions/implementation.md
+++ b/guides/subscriptions/implementation.md
@@ -1,18 +1,10 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Implementation
-desc: Subscription execution and delivery
-index: 3
----
+# Implementation
-The {{ "GraphQL::Subscriptions" | api_doc }} plugin is a base class for implementing subscriptions.
+The [GraphQL::Subscriptions](rdoc-ref:GraphQL::Subscriptions) plugin is a base class for implementing subscriptions.
-Each method corresponds to a step in the subscription lifecycle. See the API docs for method-by-method documentation: {{ "GraphQL::Subscriptions" | api_doc }}.
+Each method corresponds to a step in the subscription lifecycle. See the API docs for method-by-method documentation: [GraphQL::Subscriptions](rdoc-ref:GraphQL::Subscriptions).
-Also, see the {% internal_link "Pusher implementation guide", "subscriptions/pusher_implementation" %}, the {% internal_link "Ably implementation guide", "subscriptions/ably_implementation" %}, the {% internal_link "ActionCable implementation guide", "subscriptions/action_cable_implementation" %} or {{ "GraphQL::Subscriptions::ActionCableSubscriptions" | api_doc }} docs for an example implementation.
+Also, see the [Pusher implementation guide](/subscriptions/pusher_implementation), the [Ably implementation guide](/subscriptions/ably_implementation), the [ActionCable implementation guide](/subscriptions/action_cable_implementation) or [GraphQL::Subscriptions::ActionCableSubscriptions](rdoc-ref:GraphQL::Subscriptions::ActionCableSubscriptions) docs for an example implementation.
## Considerations
@@ -25,4 +17,4 @@ Every Ruby application is different, so consider these points when implementing
## Broadcasts
-_Broadcasting_ updates to multiple subscribers is supported by GraphQL-Ruby, but requires implementation-specific work, see more in the {% internal_link "Broadcast guide", "subscriptions/broadcast" %}.
+_Broadcasting_ updates to multiple subscribers is supported by GraphQL-Ruby, but requires implementation-specific work, see more in the [Broadcast guide](/subscriptions/broadcast).
diff --git a/guides/subscriptions/multi_tenant.md b/guides/subscriptions/multi_tenant.md
index 55ccde8b405..3ad3b42c613 100644
--- a/guides/subscriptions/multi_tenant.md
+++ b/guides/subscriptions/multi_tenant.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Multi-Tenant
-desc: Switching tenants in GraphQL Subscription execution
-index: 8
----
+# Multi-Tenant
In a multi-tenant system, data from many different accounts is stored on the same server. (An account might be an organization, a customer, a namespace, a domain, etc -- these are all _tenants_.) Gems like [Apartment](https://github.com/influitive/apartment) assist with this arrangement, but it can also be implemented in the application. Here are a few considerations for this architecture when using GraphQL subscriptions.
@@ -26,7 +18,7 @@ MySchema.execute(query_str, context: context, ...)
## Tenant-based `subscription_scope`
-When subscriptions are delivered, {% internal_link "`subscription_scope`", "subscriptions/subscription_classes#scope" %} is one element used to route data to the right subscriber. In short, it's the _implicit_ identifier for the receiver. In a multi-tenant architecture, `subscription_scope` should reference the context key that names the tenant, for example:
+When subscriptions are delivered, [`subscription_scope`](/subscriptions/subscription_classes#scope) is one element used to route data to the right subscriber. In short, it's the _implicit_ identifier for the receiver. In a multi-tenant architecture, `subscription_scope` should reference the context key that names the tenant, for example:
```ruby
class BudgetWasApproved < GraphQL::Schema::Subscription
@@ -62,7 +54,7 @@ There are a few places where subscriptions might need to load data:
Each of these operations will need to select the right tenant in order to load data properly.
-For __building the payload__, use a {% internal_link "Trace module", "queries/tracing" %}:
+For __building the payload__, use a [Trace module](/queries/tracing):
```ruby
module TenantSelectionTrace
diff --git a/guides/subscriptions/overview.md b/guides/subscriptions/overview.md
index 29a1241f27f..75765771d69 100644
--- a/guides/subscriptions/overview.md
+++ b/guides/subscriptions/overview.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Overview
-desc: Introduction to Subscriptions in GraphQL-Ruby
-index: 0
----
+# Overview
_Subscriptions_ allow GraphQL clients to observe specific events and receive updates from the server when those events occur. This supports live updates, such as websocket pushes. Subscriptions introduce several new concepts:
@@ -20,19 +12,19 @@ _Subscriptions_ allow GraphQL clients to observe specific events and receive upd
`subscription` is an entry point to your GraphQL schema, like `query` or `mutation`. It is defined by your `SubscriptionType`, a root-level `GraphQL::Schema::Object`.
-Read more in the {% internal_link "Subscription Type guide", "subscriptions/subscription_type" %}.
+Read more in the [Subscription Type guide](/subscriptions/subscription_type).
## Subscription Classes
-{{ "GraphQL::Schema::Subscription" | api_doc }} is a resolver class with subscription-specific behaviors. Each subscription field should be implemented by a subscription class.
+[GraphQL::Schema::Subscription](rdoc-ref:GraphQL::Schema::Subscription) is a resolver class with subscription-specific behaviors. Each subscription field should be implemented by a subscription class.
-Read more in the {% internal_link "Subscription Classes guide", "subscriptions/subscription_classes" %}
+Read more in the [Subscription Classes guide](/subscriptions/subscription_classes)
## Triggers
After an event occurs in our application, _triggers_ begin the update process by sending a name and payload to GraphQL.
-Read more in the {% internal_link "Triggers guide","subscriptions/triggers" %}.
+Read more in the [Triggers guide](/subscriptions/triggers).
## Implementation
@@ -42,12 +34,12 @@ Besides the GraphQL component, your application must provide some subscription-r
- __transport__: How does your application deliver payloads to clients?
- __queueing__: How does your application distribute the work of re-running subscription queries?
-Read more in the {% internal_link "Implementation guide", "subscriptions/implementation" %} or check out the {% internal_link "ActionCable implementation", "subscriptions/action_cable_implementation" %}, {% internal_link "Pusher implementation", "subscriptions/pusher_implementation" %} or {% internal_link "Ably implementation", "subscriptions/ably_implementation" %}.
+Read more in the [Implementation guide](/subscriptions/implementation) or check out the [ActionCable implementation](/subscriptions/action_cable_implementation), [Pusher implementation](/subscriptions/pusher_implementation) or [Ably implementation](/subscriptions/ably_implementation).
## Broadcasts
-By default, the subscription implementations listed above handle each subscription in total isolation. However, this behavior can be optimized by setting up broadcasts. Read more in the {% internal_link "Broadcast guide", "subscriptions/broadcast" %}.
+By default, the subscription implementations listed above handle each subscription in total isolation. However, this behavior can be optimized by setting up broadcasts. Read more in the [Broadcast guide](/subscriptions/broadcast).
## Multi-Tenant
-See the {% internal_link "Multi-tenant guide", "subscriptions/multi_tenant" %} for supporting multi-tenancy in GraphQL subscriptions.
+See the [Multi-tenant guide](/subscriptions/multi_tenant) for supporting multi-tenancy in GraphQL subscriptions.
diff --git a/guides/subscriptions/pusher_implementation.md b/guides/subscriptions/pusher_implementation.md
index 6813ffa8b84..163bf09287d 100644
--- a/guides/subscriptions/pusher_implementation.md
+++ b/guides/subscriptions/pusher_implementation.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Pusher Implementation
-desc: GraphQL subscriptions over Pusher
-index: 6
-pro: true
----
+# Pusher Implementation
[GraphQL Pro](https://graphql.pro) includes a subscription system based on [Redis](https://redis.io) and [Pusher](https://pusher.com) which works with any Ruby web framework.
@@ -120,7 +111,7 @@ For better performance reading and writing to Redis, you can pass a `connection_
### Broadcasts
-If you set up {% internal_link "Broadcasts", "/subscriptions/broadcast" %}, then you can update many clients over a single Pusher channel.
+If you set up [Broadcasts](/subscriptions/broadcast), then you can update many clients over a single Pusher channel.
Broadcast channels have stable, predictable IDs. To prevent unauthorized clients from "listening in," use an [authorized Pusher channel](#authorization) for transport. In your authorization code, you can check for a broadcast using `.broadcast_subscription_id?`:
@@ -177,7 +168,7 @@ def execute
end
```
-This will cause subscription payloads to include `compressed_result: "..."` instead of `result: "..."` when they're sent over Pusher. See docs for {% internal_link "Apollo Client", "/javascript_client/apollo_subscriptions" %} or {% internal_link "Relay Modern", "/javascript_client/relay_subscriptions" %} to read about preparing clients for compressed payloads.
+This will cause subscription payloads to include `compressed_result: "..."` instead of `result: "..."` when they're sent over Pusher. See docs for [Apollo Client](/javascript_client/apollo_subscriptions) or [Relay Modern](/javascript_client/relay_subscriptions) to read about preparing clients for compressed payloads.
By configuring `compress_pusher_payload: true` on a query-by-query basis, the subscription backend can continue to support clients running _old_ client code (by not compressing) while upgrading new clients to compressed payloads.
@@ -197,7 +188,7 @@ Your server needs to receive webhooks from Pusher when clients disconnect. This
In the Pusher web UI, Add a webhook for "Channel existence"
-{{ "/subscriptions/pusher_webhook_configuration.png" | link_to_img:"Pusher Webhook Configuration" }}
+
Then, mount the Rack app for handling webhooks from Pusher. For example, on Rails:
@@ -258,7 +249,7 @@ end
Since subscription state is stored in the database, then reloaded for pushing updates, you have to serialize and reload your query `context`.
-By default, this is done with {{ "GraphQL::Subscriptions::Serialize" | api_doc }}'s `dump` and `load` methods, but you can provide custom implementations as well. To customize the serialization logic, create a subclass of `GraphQL::Pro::PusherSubscriptions` and override `#dump_context(ctx)` and `#load_context(ctx_string)`:
+By default, this is done with `GraphQL::Subscriptions::Serialize`'s `dump` and `load` methods, but you can provide custom implementations as well. To customize the serialization logic, create a subclass of `GraphQL::Pro::PusherSubscriptions` and override `#dump_context(ctx)` and `#load_context(ctx_string)`:
```ruby
class CustomSubscriptions < GraphQL::Pro::PusherSubscriptions
@@ -288,17 +279,17 @@ That gives you fine-grained control of context reloading.
## Dashboard
-You can monitor subscription state in the {% internal_link "GraphQL-Pro Dashboard", "/pro/dashboard" %}:
+You can monitor subscription state in the [GraphQL-Pro Dashboard](/pro/dashboard):
-{{ "/subscriptions/redis_dashboard_1.png" | link_to_img:"Redis Subscription Dashboard" }}
+
-{{ "/subscriptions/redis_dashboard_2.png" | link_to_img:"Redis Subscription Detail" }}
+
## Development Tips
#### Clear subscription data
-At any time, you can reset your subscription database with the __"Reset"__ button in the {% internal_link "GraphQL-Pro Dashboard", "/pro/dashboard" %}, or in Ruby:
+At any time, you can reset your subscription database with the __"Reset"__ button in the [GraphQL-Pro Dashboard](/pro/dashboard), or in Ruby:
```ruby
# Wipe all subscription data from the DB:
@@ -313,7 +304,7 @@ To receive Pusher's webhooks in development, Pusher [suggests using ngrok](https
Install the [Pusher JS client](https://github.com/pusher/pusher-js) then see docs for:
-- {% internal_link "Apollo Client", "/javascript_client/apollo_subscriptions" %}
-- {% internal_link "Relay Modern", "/javascript_client/relay_subscriptions" %}
-- {% internal_link "GraphiQL", "/javascript_client/graphiql_subscriptions" %}
-- {% internal_link "urql", "/javascript_client/urql_subscriptions" %}
+- [Apollo Client](/javascript_client/apollo_subscriptions)
+- [Relay Modern](/javascript_client/relay_subscriptions)
+- [GraphiQL](/javascript_client/graphiql_subscriptions)
+- [urql](/javascript_client/urql_subscriptions)
diff --git a/guides/subscriptions/subscription_classes.md b/guides/subscriptions/subscription_classes.md
index af0914dd719..1b65cc8d43f 100644
--- a/guides/subscriptions/subscription_classes.md
+++ b/guides/subscriptions/subscription_classes.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Subscription Classes
-desc: Subscription resolvers for pushing updates to clients
-index: 1
----
-
-You can extend {{ "GraphQL::Schema::Subscription" | api_doc }} to create fields that can be subscribed to.
+# Subscription Classes
+
+You can extend [GraphQL::Schema::Subscription](rdoc-ref:GraphQL::Schema::Subscription) to create fields that can be subscribed to.
These classes support several behaviors:
@@ -34,7 +26,7 @@ class Subscriptions::BaseSubscription < GraphQL::Schema::Subscription
end
```
-(This base class is a lot like the {% internal_link "mutation base class", "/mutations/mutation_classes" %}. They're both subclasses of {{ "GraphQL::Schema::Resolver" | api_doc }}.)
+(This base class is a lot like the [mutation base class](/mutations/mutation_classes). They're both subclasses of [GraphQL::Schema::Resolver](rdoc-ref:GraphQL::Schema::Resolver).)
## Extend the base class and hook it up
@@ -46,7 +38,7 @@ class Subscriptions::MessageWasPosted < Subscriptions::BaseSubscription
end
```
-Then, hook up the new class to the {% internal_link "Subscription root type", "subscriptions/subscription_type" %} with the `subscription:` option:
+Then, hook up the new class to the [Subscription root type](/subscriptions/subscription_type) with the `subscription:` option:
```ruby
class Types::SubscriptionType < Types::BaseObject
@@ -66,7 +58,7 @@ subscription {
## Arguments
-Subscription fields take {% internal_link "arguments", "/fields/arguments" %} just like normal fields. They also accept a {% internal_link "`loads:` option", "/mutations/mutation_classes#auto-loading-arguments" %} just like mutations. For example:
+Subscription fields take [arguments](/fields/arguments) just like normal fields. They also accept a [`loads:` option](/mutations/mutation_classes#auto-loading-arguments) just like mutations. For example:
```ruby
class Subscriptions::MessageWasPosted < Subscriptions::BaseSubscription
@@ -148,7 +140,7 @@ payload_type Types::MessageType
## Scope
-Usually, GraphQL-Ruby uses explicitly-passed arguments to determine when a {% internal_link "trigger", "subscriptions/triggers" %} applies to an active subscription. But, you can use `subscription_scope` to configure _implicit_ conditions on updates. When `subscription_scope` is configured, only triggers with a matching `scope:` value will cause clients to receive updates.
+Usually, GraphQL-Ruby uses explicitly-passed arguments to determine when a [trigger](/subscriptions/triggers) applies to an active subscription. But, you can use `subscription_scope` to configure _implicit_ conditions on updates. When `subscription_scope` is configured, only triggers with a matching `scope:` value will cause clients to receive updates.
`subscription_scope` accepts a symbol and the given symbol will be looked up in `context` to find a scope value.
@@ -191,7 +183,7 @@ MyAppSchema.subscriptions.trigger(
)
```
-Scope is also used for determining whether subscribers can receive the same {% internal_link "broadcast", "subscriptions/implementation#broadcast" %}.
+Scope is also used for determining whether subscribers can receive the same [broadcast](/subscriptions/implementation#broadcasts).
## Check Permissions with #authorized?
@@ -270,7 +262,7 @@ subscription($roomId: ID!) {
## Subsequent Updates with #update
-After a client has registered a subscription, the application may trigger subscription updates with `MySchema.subscriptions.trigger(...)` (see the {% internal_link "Triggers guide", "/subscriptions/triggers" %} for more). Then, `def update` will be called for each client's subscription. In this method you can:
+After a client has registered a subscription, the application may trigger subscription updates with `MySchema.subscriptions.trigger(...)` (see the [Triggers guide](/subscriptions/triggers) for more). Then, `def update` will be called for each client's subscription. In this method you can:
- Unsubscribe the client with `unsubscribe`
- Return a value with `super` (which returns `object`) or by returning a different value.
@@ -368,4 +360,4 @@ class Subscriptions::JobFinished < GraphQL::Schema::Subscription
end
```
-See the {% internal_link "Extra Field Metadata", "/fields/introduction#extra-field-metadata" %} for more information about available metadata.
+See the [Extra Field Metadata](/fields/introduction#extra-field-metadata) for more information about available metadata.
diff --git a/guides/subscriptions/subscription_type.md b/guides/subscriptions/subscription_type.md
index e8b1c5290e9..b3d61791b8e 100644
--- a/guides/subscriptions/subscription_type.md
+++ b/guides/subscriptions/subscription_type.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Subscription Type
-desc: The root type for subscriptions
-index: 1
----
+# Subscription Type
`Subscription` is the entry point for all subscriptions in a GraphQL system. Each field corresponds to an event which may be subscribed to:
@@ -57,6 +49,6 @@ class MySchema < GraphQL::Schema
end
```
-See {% internal_link "Implementing Subscriptions","subscriptions/implementation" %} for more about actually delivering updates.
+See [Implementing Subscriptions](/subscriptions/implementation) for more about actually delivering updates.
-See {% internal_link "Subscription Classes", "subscriptions/subscription_classes" %} for more about implementing subscription root fields.
+See [Subscription Classes](/subscriptions/subscription_classes) for more about implementing subscription root fields.
diff --git a/guides/subscriptions/triggers.md b/guides/subscriptions/triggers.md
index c55cf7e5a53..58287f70390 100644
--- a/guides/subscriptions/triggers.md
+++ b/guides/subscriptions/triggers.md
@@ -1,16 +1,8 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Subscriptions
-title: Triggers
-desc: Sending updates from your application to GraphQL
-index: 2
----
+# Triggers
From your application, you can push updates to GraphQL clients with `.trigger`.
-Events are triggered _by name_, and the name must match fields on your {% internal_link "Subscription Type","subscriptions/subscription_type" %}
+Events are triggered _by name_, and the name must match fields on your [Subscription Type](/subscriptions/subscription_type)
```ruby
# Update the system with the new blog post:
@@ -28,7 +20,7 @@ The arguments are:
To send updates to _certain clients only_, you can use `scope:` to narrow the trigger's reach.
-Scopes are based on query context: a value in `context:` is used as the scope; an equivalent value must be passed with `.trigger(... scope:)` to update that client. (The value is serialized with {{ "GraphQL::Subscriptions::Serialize" | api_doc }})
+Scopes are based on query context: a value in `context:` is used as the scope; an equivalent value must be passed with `.trigger(... scope:)` to update that client. (The value is serialized with `GraphQL::Subscriptions::Serialize`.)
To specify that a topic is scoped, add a `subscription_scope` option to the Subscription class:
@@ -42,7 +34,7 @@ class Subscriptions::CommentAdded < Subscription::BaseSubscription
end
```
-(Read more in the {% internal_link "Subscription Classes guide", "subscriptions/subscription_classes#scope" %}.)
+(Read more in the [Subscription Classes guide](/subscriptions/subscription_classes#scope).)
Then, subscription operations should have a `context: { current_user_id: ... }` value, for example:
diff --git a/guides/testing/helpers.md b/guides/testing/helpers.md
index f7e248f8ba2..99bec0f6019 100644
--- a/guides/testing/helpers.md
+++ b/guides/testing/helpers.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Testing
-title: Helpers
-desc: Running GraphQL fields in isolation
-index: 3
----
+# Helpers
GraphQL-Ruby ships with a test helper method, `run_graphql_field`, that can execute a GraphQL field in isolation. To use it in your test suite, include the module with your schema class:
@@ -15,7 +7,7 @@ GraphQL-Ruby ships with a test helper method, `run_graphql_field`, that can exec
include GraphQL::Testing::Helpers.for(MySchema)
```
-Then, you can run fields using {{ "Testing::Helpers#run_graphql_field" | api_doc }}:
+Then, you can run fields using [Testing::Helpers#run_graphql_field](rdoc-ref:GraphQL::Testing::Helpers#run_graphql_field):
```ruby
post = Post.first
@@ -37,16 +29,16 @@ Additionally, it accepts some keyword arguments:
- Checks `.visible?` on the named Object Type, raising an error if it isn't visible
- Wraps the given runtime object in the GraphQL Object Type
-- Checks `.authorized?` on the type, calling {{ "Schema.unauthorized_object" | api_doc }} if authorization fails
+- Checks `.authorized?` on the type, calling [Schema.unauthorized_object](rdoc-ref:GraphQL::Schema.unauthorized_object) if authorization fails
- Prepares arguments for field resolution
- Checks `#visible?` on the field, raising an error if the field isn't visible
-- Checks `#authorized?` on the field, calling {{ "Schema.unauthorized_field" | api_doc }} if it fails
-- Calls any {% internal_link "field extensions", "/type_definitions/field_extensions" %}
-- Runs {% internal_link "Dataloader", "/dataloader/overview" %} and/or GraphQL-Batch, as needed
+- Checks `#authorized?` on the field, calling [Schema.unauthorized_field](rdoc-ref:GraphQL::Schema.unauthorized_field) if it fails
+- Calls any [field extensions](/type_definitions/field_extensions)
+- Runs [Dataloader](/dataloader/overview) and/or GraphQL-Batch, as needed
## Resolving fields on the same object
-You can use {{ "Testing::Helpers#with_resolution_context" | api_doc }} to use the same type, runtime object, and GraphQL context for multiple field resolutions. For example:
+You can use [Testing::Helpers#with_resolution_context](rdoc-ref:GraphQL::Testing::Helpers#with_resolution_context) to use the same type, runtime object, and GraphQL context for multiple field resolutions. For example:
```ruby
# Assuming `include GraphQL::Testing::Helpers.for(MySchema)`
diff --git a/guides/testing/integration_tests.md b/guides/testing/integration_tests.md
index d21b6acac80..6b668581456 100644
--- a/guides/testing/integration_tests.md
+++ b/guides/testing/integration_tests.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Testing
-title: Integration Tests
-desc: Run the whole GraphQL stack in tests
-index: 2
----
-
-Besides testing {% internal_link "schema structure", "/testing/schema_structure" %}, you should also test your GraphQL system's behavior. There are really a few levels to this:
+# Integration Tests
+
+Besides testing [schema structure](/testing/schema_structure), you should also test your GraphQL system's behavior. There are really a few levels to this:
- __Application-level__ behaviors, like business logic, permissions, and persistence. These behaviors may be shared by your API and user interface.
- __Interface-level__ behaviors, like GraphQL fields, mutations, error scenarios, and HTTP-specific behaviors. These are unique to your GraphQL system.
diff --git a/guides/testing/overview.md b/guides/testing/overview.md
index 6c12f827be0..99f2402ddba 100644
--- a/guides/testing/overview.md
+++ b/guides/testing/overview.md
@@ -1,18 +1,7 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Testing
-title: Overview
-desc: Testing a GraphQL system
-index: 0
-redirect_from:
- - /schema/testing
----
-
+# Overview
So, you've spiked a GraphQL API, and now you're ready to tighten things up and add some proper tests. These guides will help you think about how to ensure stability and compatibility for your GraphQL system.
-- {% internal_link "Structure testing", "/testing/schema_structure" %} verifies that schema changes are backwards-compatible. This way, you don't break existing clients.
-- {% internal_link "Integration testing", "/testing/integration_tests" %} exercises the various behaviors of the GraphQL system, making sure that it returns the right data to the right clients.
-- {% internal_link "Testing helpers", "/testing/helpers" %} for running GraphQL fields without writing a whole query
+- [Structure testing](/testing/schema_structure) verifies that schema changes are backwards-compatible. This way, you don't break existing clients.
+- [Integration testing](/testing/integration_tests) exercises the various behaviors of the GraphQL system, making sure that it returns the right data to the right clients.
+- [Testing helpers](/testing/helpers) for running GraphQL fields without writing a whole query
diff --git a/guides/testing/profiling.md b/guides/testing/profiling.md
index 68c577a05f3..3b175798880 100644
--- a/guides/testing/profiling.md
+++ b/guides/testing/profiling.md
@@ -1,16 +1,8 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Testing
-title: Profiling
-desc: Profiling the performance of GraphQL-Ruby
-index: 4
----
+# Profiling
If you want to know more about how time is spent during GraphQL queries, including GraphQL-Ruby internals, you can use Ruby profiling tools to take a closer look.
-If you want to investigate GraphQL-Ruby performance together, prepare a runtime profile and memory profile as described below and {% open_an_issue "Performance investigation" %} on GitHub, including those files.
+If you want to investigate GraphQL-Ruby performance together, prepare a runtime profile and memory profile as described below and [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=Performance+investigation&body=) on GitHub, including those files.
## StackProf
diff --git a/guides/testing/schema_structure.md b/guides/testing/schema_structure.md
index e2e1e85fc45..9e9de9de5f7 100644
--- a/guides/testing/schema_structure.md
+++ b/guides/testing/schema_structure.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Testing
-title: Schema Structure
-desc: Make sure that your schema changes are backwards-compatible
-index: 1
----
+# Schema Structure
Structural changes to a GraphQL schema come in two categories:
@@ -21,7 +13,7 @@ Here are few tips for managing schema structure changes.
Make structure changes part of the normal code review process by adding a `schema.graphql` artifact to your project. This way, any changes to schema structure will show up clearly in a pull request as a diff to that file.
-You can read about this approach in ["Tracking Schema Changes with GraphQL-Ruby"](https://rmosolgo.github.io/ruby/graphql/2017/03/16/tracking-schema-changes-with-graphql-ruby) or the built-in {{ "GraphQL::RakeTask" | api_doc }} for generating schema dumps.
+You can read about this approach in ["Tracking Schema Changes with GraphQL-Ruby"](https://rmosolgo.github.io/ruby/graphql/2017/03/16/tracking-schema-changes-with-graphql-ruby) or the built-in [GraphQL::RakeTask](rdoc-ref:GraphQL::RakeTask) for generating schema dumps.
## Automatically check for breaking changes
diff --git a/guides/type_definitions/directives.md b/guides/type_definitions/directives.md
index 21182f0c454..85ef9bc6445 100644
--- a/guides/type_definitions/directives.md
+++ b/guides/type_definitions/directives.md
@@ -1,13 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Directives
-desc: Special instructions for the GraphQL runtime
-index: 10
----
-
+# Directives
Directives are system-defined keywords with two kinds of uses:
@@ -33,12 +24,12 @@ query ProfileView($renderingDetailedProfile: Boolean!){
Here's how the two built-in directives work:
-- `@skip(if: ...)` skips the selection if the `if: ...` value is truthy ({{ "GraphQL::Schema::Directive::Skip" | api_doc }})
-- `@include(if: ...)` includes the selection if the `if: ...` value is truthy ({{ "GraphQL::Schema::Directive::Include" | api_doc }})
+- `@skip(if: ...)` skips the selection if the `if: ...` value is truthy ([GraphQL::Schema::Directive::Skip](rdoc-ref:GraphQL::Schema::Directive::Skip))
+- `@include(if: ...)` includes the selection if the `if: ...` value is truthy ([GraphQL::Schema::Directive::Include](rdoc-ref:GraphQL::Schema::Directive::Include))
### Custom Runtime Directives
-Custom directives extend {{ "GraphQL::Schema::Directive" | api_doc }}:
+Custom directives extend [GraphQL::Schema::Directive](rdoc-ref:GraphQL::Schema::Directive):
```ruby
# app/graphql/directives/my_directive.rb
@@ -67,7 +58,7 @@ query {
}
```
-{{ "GraphQL::Schema::Directive::Feature" | api_doc }} and {{ "GraphQL::Schema::Directive::Transform" | api_doc }} are included in the library as examples.
+[GraphQL::Schema::Directive::Feature](rdoc-ref:GraphQL::Schema::Directive::Feature) and [GraphQL::Schema::Directive::Transform](rdoc-ref:GraphQL::Schema::Directive::Transform) are included in the library as examples.
### Runtime hooks
@@ -76,7 +67,7 @@ Directive classes may implement the following class methods to interact with the
- `def self.include?(obj, args, ctx)`: If this hook returns `false`, the nodes flagged by this directive will be skipped at runtime.
- `def self.resolve(obj, args, ctx)`: Wraps the resolution of flagged nodes. Resolution is passed as a __block__, so `yield` will continue resolution.
-Looking for a runtime hook that isn't listed here? {% open_an_issue "New directive hook: @something", " " %} to start the conversation!
+Looking for a runtime hook that isn't listed here? [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?title=New+directive+hook%3A+%40something&body=%3C%21--+Describe+how+the+directive+would+be+used+and+then+how+you+might+implement+it+--%3E+) to start the conversation!
## Schema Directives
@@ -94,7 +85,7 @@ In the schema definition, directives express metadata about types, fields, and a
### Custom Schema Directives
-To make a custom schema directive, extend {{ "GraphQL::Schema::Directive" | api_doc }}:
+To make a custom schema directive, extend [GraphQL::Schema::Directive](rdoc-ref:GraphQL::Schema::Directive):
```ruby
# app/graphql/directives/permission.rb
@@ -122,14 +113,14 @@ field :salary, Integer, null: false,
After that:
- the configured object's `.directives` method will return an array containing an instance of the specified directive
-- IDL dumps (from {{ "Schema.to_definition" | api_doc }}) will include the configured directives
+- IDL dumps (from [Schema.to_definition](rdoc-ref:GraphQL::Schema.to_definition)) will include the configured directives
-Similarly, {{ "Schema.from_definition" | api_doc }} parses directives from IDL strings.
+Similarly, [Schema.from_definition](rdoc-ref:GraphQL::Schema.from_definition) parses directives from IDL strings.
For a couple of built-in examples, check out:
-- {{ "GraphQL::Schema::Directive::Deprecated" | api_doc }} which implements `deprecation_reason` (via {{ "GraphQL::Schema::Member::HasDeprecationReason" | api_doc}})
-- {{ "GraphQL::Schema::Directive::Flagged" | api_doc }}, which is an example of using schema directives to implement {% internal_link "visibility", "/authorization/visibility" %}
+- [GraphQL::Schema::Directive::Deprecated](rdoc-ref:GraphQL::Schema::Directive::Deprecated) which implements `deprecation_reason` (via [GraphQL::Schema::Member::HasDeprecationReason](rdoc-ref:GraphQL::Schema::Member::HasDeprecationReason))
+- [GraphQL::Schema::Directive::Flagged](rdoc-ref:GraphQL::Schema::Directive::Flagged), which is an example of using schema directives to implement [visibility](/authorization/visibility)
## Custom Name
@@ -143,7 +134,7 @@ end
## Arguments
-Like fields, directives may have {% internal_link "arguments", "/fields/arguments" %} :
+Like fields, directives may have [arguments](/fields/arguments) :
```ruby
argument :if, Boolean,
diff --git a/guides/type_definitions/enums.md b/guides/type_definitions/enums.md
index 7575b811062..42cefa78032 100644
--- a/guides/type_definitions/enums.md
+++ b/guides/type_definitions/enums.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Enums
-desc: Enums are sets of discrete values
-index: 2
----
+# Enums
Enum types are sets of discrete values. An enum field must return one of the possible values of the enum. In the [GraphQL Schema Definition Language](https://graphql.org/learn/schema/#enum-types) (SDL), enums are described like this:
@@ -39,7 +31,7 @@ params["variables"]
## Defining Enum Types
-In your application, enums extend {{ "GraphQL::Schema::Enum" | api_doc }} and define values with the `value(...)` method:
+In your application, enums extend [GraphQL::Schema::Enum](rdoc-ref:GraphQL::Schema::Enum) and define values with the `value(...)` method:
```ruby
# First, a base class
diff --git a/guides/type_definitions/extensions.md b/guides/type_definitions/extensions.md
index 214570d734b..fc9d30bd3ef 100644
--- a/guides/type_definitions/extensions.md
+++ b/guides/type_definitions/extensions.md
@@ -1,14 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Extending the GraphQL-Ruby Type Definition System
-desc: Adding metadata and custom helpers to the DSL
-index: 8
-redirect_from:
- - /schema/extending_the_dsl/
----
+# Extending the GraphQL-Ruby Type Definition System
While integrating GraphQL into your app, you can customize the definition DSL. For example, you might:
diff --git a/guides/type_definitions/field_extensions.md b/guides/type_definitions/field_extensions.md
index 45a06faba74..972a1cc01a3 100644
--- a/guides/type_definitions/field_extensions.md
+++ b/guides/type_definitions/field_extensions.md
@@ -1,18 +1,10 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Field Extensions
-desc: Programmatically modify field configuration and resolution
-index: 10
----
-
-{{ "GraphQL::Schema::FieldExtension" | api_doc }} provides a way to modify user-defined fields in a programmatic way. For example, Relay connections are implemented as a field extension ({{ "GraphQL::Schema::Field::ConnectionExtension" | api_doc }}).
+# Field Extensions
+
+[GraphQL::Schema::FieldExtension](rdoc-ref:GraphQL::Schema::FieldExtension) provides a way to modify user-defined fields in a programmatic way. For example, Relay connections are implemented as a field extension ([GraphQL::Schema::Field::ConnectionExtension](rdoc-ref:GraphQL::Schema::Field::ConnectionExtension)).
## Making a new extension
-Field extensions are subclasses of {{ "GraphQL::Schema::FieldExtension" | api_doc }}:
+Field extensions are subclasses of [GraphQL::Schema::FieldExtension](rdoc-ref:GraphQL::Schema::FieldExtension):
```ruby
class MyExtension < GraphQL::Schema::FieldExtension
@@ -50,7 +42,7 @@ This way, an extension can encapsulate a behavior requiring several configuratio
## Adding default argument configurations
-Extensions may provide _default_ argument configurations which are applied if the field doesn't define the argument for itself. The configuration is passed to {{ "Schema::FieldExtension.default_argument" | api_doc }}. For example, to define a `:query` argument if the field doesn't already have one:
+Extensions may provide _default_ argument configurations which are applied if the field doesn't define the argument for itself. The configuration is passed to [Schema::FieldExtension.default_argument](rdoc-ref:GraphQL::Schema::FieldExtension.default_argument). For example, to define a `:query` argument if the field doesn't already have one:
```ruby
class SearchableExtension < GraphQL::Schema::FieldExtension
@@ -66,9 +58,9 @@ Additionally, extensions may implement `def after_define` which is called _after
Extensions have two hooks that wrap field resolution. Since GraphQL-Ruby supports deferred execution, these hooks _might not_ be called back-to-back.
-First, {{ "GraphQL::Schema::FieldExtension#resolve" | api_doc }} is called. `resolve` should `yield(object, arguments)` to continue execution. If it doesn't `yield`, then the underlying field won't be called. Whatever `#resolve` returns will be used for continuing execution.
+First, [GraphQL::Schema::FieldExtension#resolve](rdoc-ref:GraphQL::Schema::FieldExtension#resolve) is called. `resolve` should `yield(object, arguments)` to continue execution. If it doesn't `yield`, then the underlying field won't be called. Whatever `#resolve` returns will be used for continuing execution.
-After resolution and _after_ syncing lazy values (like `Promise`s from `graphql-batch`), {{ "GraphQL::Schema::FieldExtension#after_resolve" | api_doc }} is called. Whatever that method returns will be used as the field's return value.
+After resolution and _after_ syncing lazy values (like `Promise`s from `graphql-batch`), [GraphQL::Schema::FieldExtension#after_resolve](rdoc-ref:GraphQL::Schema::FieldExtension#after_resolve) is called. Whatever that method returns will be used as the field's return value.
See the linked API docs for the parameters of those methods.
@@ -124,7 +116,7 @@ field :name, String, null: false, extensions: [LimitExtension => { limit: 20 }]
## Using `extras`
-Extensions can have the same `extras` as fields (see {% internal_link "Extra Field Metadata", "fields/introduction#extra-field-metadata" %}). Add them by calling `extras` in the class definition:
+Extensions can have the same `extras` as fields (see [Extra Field Metadata](/fields/introduction#extra-field-metadata)). Add them by calling `extras` in the class definition:
```ruby
class MyExtension < GraphQL::Schema::FieldExtension
@@ -136,7 +128,7 @@ Any configured `extras` will be present in the given `arguments`, but removed be
## Adding an extension by default
-If you want to apply an extension to _all_ your fields, you can do this in your {% internal_link "BaseField", "/type_definitions/extensions.html#customizing-fields" %}'s `def initialize`, for example:
+If you want to apply an extension to _all_ your fields, you can do this in your [BaseField](/type_definitions/extensions.html#customizing-fields)'s `def initialize`, for example:
```ruby
class Types::BaseField < GraphQL::Schema::Field
diff --git a/guides/type_definitions/input_objects.md b/guides/type_definitions/input_objects.md
index 3cfadd00775..afb4e9bd9c5 100644
--- a/guides/type_definitions/input_objects.md
+++ b/guides/type_definitions/input_objects.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Input Objects
-desc: Input objects are sets of key-value pairs which can be used as field arguments.
-index: 3
----
+# Input Objects
Input object types are complex inputs for GraphQL operations. They're great for fields that need a lot of structured input, like mutations or search fields. In a GraphQL request, it might look like this:
@@ -36,7 +28,7 @@ This input object has three possible keys:
## Defining Input Object Types
-Input object types extend {{ "GraphQL::Schema::InputObject" | api_doc }} and define key-value pairs with the `argument(...)` method. For example:
+Input object types extend [GraphQL::Schema::InputObject](rdoc-ref:GraphQL::Schema::InputObject) and define key-value pairs with the `argument(...)` method. For example:
```ruby
# app/graphql/types/base_input_object.rb
@@ -52,7 +44,7 @@ class Types::PostAttributes < Types::BaseInputObject
end
```
-For a full description of the `argument(...)` method, see the {% internal_link "argument section of the Objects guide","/fields/arguments.html" %}.
+For a full description of the `argument(...)` method, see the [argument section of the Objects guide](/fields/arguments.html).
## Using Input Objects
@@ -101,8 +93,8 @@ end
You can also add or override methods on input object classes to customize them. They have two instance variables by default:
-- `@arguments`: A {{ "GraphQL::Execution::Interpreter::Arguments" | api_doc }} instance
-- `@context`: The current {{ "GraphQL::Query::Context" | api_doc }}
+- `@arguments`: A [GraphQL::Execution::Interpreter::Arguments](rdoc-ref:GraphQL::Execution::Interpreter::Arguments) instance
+- `@context`: The current [GraphQL::Query::Context](rdoc-ref:GraphQL::Query::Context)
Any extra methods you define on the class can be used for field resolution, as demonstrated above.
diff --git a/guides/type_definitions/interfaces.md b/guides/type_definitions/interfaces.md
index 84738ff4ede..59a38b5966e 100644
--- a/guides/type_definitions/interfaces.md
+++ b/guides/type_definitions/interfaces.md
@@ -1,14 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Interfaces
-desc: Interfaces are lists of fields which objects may implement
-index: 4
-redirect_from:
- - /types/abstract_types/
----
+# Interfaces
Interfaces are lists of fields which may be implemented by object types.
@@ -63,11 +53,11 @@ Whether the objects are `Company` or `Individual`, it doesn't matter -- you stil
This means, "if the customer is an `Individual`, also get the customer's company name".
-Interfaces are a good choice whenever a set of objects are used interchangeably, and they have several significant fields in common. When they don't have fields in common, use a {% internal_link "Union", "/type_definitions/unions" %} instead.
+Interfaces are a good choice whenever a set of objects are used interchangeably, and they have several significant fields in common. When they don't have fields in common, use a [Union](/type_definitions/unions) instead.
## Defining Interface Types
-Interfaces are Ruby modules which include {{ "GraphQL::Schema::Interface" | api_doc }}. First, make a base module:
+Interfaces are Ruby modules which include [GraphQL::Schema::Interface](rdoc-ref:GraphQL::Schema::Interface). First, make a base module:
```ruby
module Types::BaseInterface
@@ -139,7 +129,7 @@ end
This method will be called by objects who implement the interface. To override this implementation,
object classes can override the `#price` method.
-Read more in the {% internal_link "Fields guide", "/fields/introduction" %}.
+Read more in the [Fields guide](/fields/introduction).
### Definition Methods
diff --git a/guides/type_definitions/lists.md b/guides/type_definitions/lists.md
index aff9a4db2b2..b84cd6299a2 100644
--- a/guides/type_definitions/lists.md
+++ b/guides/type_definitions/lists.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Lists
-desc: Ordered lists containing other types
-index: 6
----
+# Lists
GraphQL has _list types_ which are ordered lists containing items of other types. The following examples use the [GraphQL Schema Definition Language](https://graphql.org/learn/schema/#list) (SDL).
diff --git a/guides/type_definitions/non_nulls.md b/guides/type_definitions/non_nulls.md
index 330d5aa8e7e..ee5ddb2a470 100644
--- a/guides/type_definitions/non_nulls.md
+++ b/guides/type_definitions/non_nulls.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Non-Null Types
-desc: Values which must be present
-index: 7
----
+# Non-Null Types
GraphQL's concept of _non-null_ is expressed in the [Schema Definition Language](https://graphql.org/learn/schema/#non-null) (SDL) with `!`, for example:
diff --git a/guides/type_definitions/objects.md b/guides/type_definitions/objects.md
index 1718c2810b4..2de420f6853 100644
--- a/guides/type_definitions/objects.md
+++ b/guides/type_definitions/objects.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Objects
-desc: Objects expose data and link to other objects
-index: 0
----
+# Objects
GraphQL object types are the bread and butter of GraphQL APIs. Each object has _fields_ which expose data and may be queried by name. For example, we can query a `User` like this:
@@ -58,7 +50,7 @@ The rest of this guide will describe how to define GraphQL object types in Ruby.
## Object classes
-Classes extending {{ "GraphQL::Schema::Object" | api_doc }} describe [Object types](https://graphql.org/learn/schema/#object-types-and-fields) and customize their behavior.
+Classes extending [GraphQL::Schema::Object](rdoc-ref:GraphQL::Schema::Object) describe [Object types](https://graphql.org/learn/schema/#object-types-and-fields) and customize their behavior.
Object fields can be created with the `field(...)` class method, [described in detail below](#fields)
@@ -91,7 +83,7 @@ end
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.
-See the {% internal_link "Fields guide", "/fields/introduction" %} for details about object fields.
+See the [Fields guide](/fields/introduction) for details about object fields.
## Implementing interfaces
@@ -108,4 +100,4 @@ When an object `implements` interfaces, it:
- inherits the GraphQL field definitions from that object
- includes that module into the object definition
-Read more about interfaces in the {% internal_link "Interfaces guide", "/type_definitions/interfaces" %}
+Read more about interfaces in the [Interfaces guide](/type_definitions/interfaces)
diff --git a/guides/type_definitions/scalars.md b/guides/type_definitions/scalars.md
index b5d15647106..708c5e40dbf 100644
--- a/guides/type_definitions/scalars.md
+++ b/guides/type_definitions/scalars.md
@@ -1,14 +1,6 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Scalars
-desc: Scalars are "simple" data types like integers and strings
-index: 1
----
-
-Scalars are "leaf" values in GraphQL. There are several built-in scalars, and you can define custom scalars, too. ({% internal_link "Enums", "/type_definitions/enums" %} are also leaf values.) The built-in scalars are:
+# Scalars
+
+Scalars are "leaf" values in GraphQL. There are several built-in scalars, and you can define custom scalars, too. ([Enums](/type_definitions/enums) are also leaf values.) The built-in scalars are:
- `String`, like a JSON or Ruby string
- `Int`, like a JSON or Ruby integer
@@ -17,7 +9,7 @@ Scalars are "leaf" values in GraphQL. There are several built-in scalars, and yo
- `ID`, which a specialized `String` for representing unique object identifiers
- `ISO8601DateTime`, an ISO 8601-encoded datetime
- `ISO8601Date`, an ISO 8601-encoded date
-- `ISO8601Duration`, an ISO 8601-encoded duration. ⚠ This requires `ActiveSupport::Duration` to be loaded and will raise {{ "GraphQL::Error" | api_doc }} if it's `.coerce_*` methods are called when it is not defined.
+- `ISO8601Duration`, an ISO 8601-encoded duration. ⚠ This requires `ActiveSupport::Duration` to be loaded and will raise [GraphQL::Error](rdoc-ref:GraphQL::Error) if it's `.coerce_*` methods are called when it is not defined.
- `JSON`, ⚠ This returns arbitrary JSON (Ruby hashes, arrays, strings, integers, floats, booleans and nils). Take care: by using this type, you completely lose all GraphQL type safety. Consider building object types for your data instead.
- `BigInt`, a numeric value which may exceed the size of a 32-bit integer
@@ -63,7 +55,7 @@ scalar DateTime
## Custom Scalars
-You can implement your own scalars by extending {{ "GraphQL::Schema::Scalar" | api_doc }}. For example:
+You can implement your own scalars by extending [GraphQL::Schema::Scalar](rdoc-ref:GraphQL::Schema::Scalar). For example:
```ruby
# app/graphql/types/base_scalar.rb
@@ -99,6 +91,6 @@ Your class must define two class methods:
- `self.coerce_input` takes a GraphQL input and converts it into a Ruby value
- `self.coerce_result` takes the return value of a field and prepares it for the GraphQL response JSON
-When incoming data is incorrect, the method may raise {{ "GraphQL::CoercionError" | api_doc }}, which will be returned to the client in the `"errors"` key.
+When incoming data is incorrect, the method may raise [GraphQL::CoercionError](rdoc-ref:GraphQL::CoercionError), which will be returned to the client in the `"errors"` key.
Scalar classes are never initialized; only their `.coerce_*` methods are called at runtime.
diff --git a/guides/type_definitions/unions.md b/guides/type_definitions/unions.md
index 4b99f55f6c4..62bc8280e42 100644
--- a/guides/type_definitions/unions.md
+++ b/guides/type_definitions/unions.md
@@ -1,12 +1,4 @@
----
-layout: guide
-doc_stub: false
-search: true
-section: Type Definitions
-title: Unions
-desc: Unions are sets of types which may appear in the same place (but don't share fields).
-index: 5
----
+# Unions
A union type is a set of object types which may appear in the same spot. Here's a union, expressed in [GraphQL Schema Definition Language](https://graphql.org/learn/schema/#union-types) (SDL):
@@ -36,7 +28,7 @@ searchMedia(term: "puppies") {
Here, the `searchMedia` field returns `[MediaItem!]`, a list where each member is part of the `MediaItem` union. So, for each member, we want to select different fields depending on which kind of object that member is.
-{% internal_link "Interfaces", "/type_definitions/interfaces" %} are a similar concept, but in an interface, all types must share some common fields. Unions are a good choice when the object types don't have any significant fields in common.
+[Interfaces](/type_definitions/interfaces) are a similar concept, but in an interface, all types must share some common fields. Unions are a good choice when the object types don't have any significant fields in common.
Since union members share _no_ fields, selections are _always_ made with typed fragments (`... on SomeType`, as seen above).
@@ -73,4 +65,4 @@ The `possible_types(*types)` method accepts one or more types which belong to th
Union classes are never instantiated; At runtime, only their `.resolve_type` methods may be called (if defined).
-For information about `.resolve_type`, see the {% internal_link "Interfaces guide", "/type_definitions/interfaces#resolve-type" %}.
+For information about `.resolve_type`, see the [Interfaces guide](/type_definitions/interfaces#resolve-type).
diff --git a/lib/generators/graphql/loader_generator.rb b/lib/generators/graphql/loader_generator.rb
index d953f005d7c..7699ee6603d 100644
--- a/lib/generators/graphql/loader_generator.rb
+++ b/lib/generators/graphql/loader_generator.rb
@@ -5,8 +5,13 @@
module Graphql
module Generators
- # @example Generate a `GraphQL::Batch` loader by name.
- # rails g graphql:loader RecordLoader
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Batch` loader by name.**
+ #
+ # ```ruby
+ # rails g graphql:loader RecordLoader
+ # ```
class LoaderGenerator < Rails::Generators::NamedBase
include Core
diff --git a/lib/generators/graphql/mutation_create_generator.rb b/lib/generators/graphql/mutation_create_generator.rb
index 049cb7284d2..07d251939b5 100644
--- a/lib/generators/graphql/mutation_create_generator.rb
+++ b/lib/generators/graphql/mutation_create_generator.rb
@@ -5,8 +5,13 @@ module Graphql
module Generators
# TODO: What other options should be supported?
#
- # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
- # rails g graphql:mutation CreatePostMutation
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Schema::RelayClassicMutation` by name**
+ #
+ # ```ruby
+ # rails g graphql:mutation CreatePostMutation
+ # ```
class MutationCreateGenerator < OrmMutationsBase
desc "Scaffold a Relay Classic ORM create mutation for the given model class"
diff --git a/lib/generators/graphql/mutation_delete_generator.rb b/lib/generators/graphql/mutation_delete_generator.rb
index bf33a7606b6..56412f2f3fc 100644
--- a/lib/generators/graphql/mutation_delete_generator.rb
+++ b/lib/generators/graphql/mutation_delete_generator.rb
@@ -5,8 +5,13 @@ module Graphql
module Generators
# TODO: What other options should be supported?
#
- # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
- # rails g graphql:mutation DeletePostMutation
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Schema::RelayClassicMutation` by name**
+ #
+ # ```ruby
+ # rails g graphql:mutation DeletePostMutation
+ # ```
class MutationDeleteGenerator < OrmMutationsBase
desc "Scaffold a Relay Classic ORM delete mutation for the given model class"
diff --git a/lib/generators/graphql/mutation_generator.rb b/lib/generators/graphql/mutation_generator.rb
index 5eebd2adaa1..b33834daac5 100644
--- a/lib/generators/graphql/mutation_generator.rb
+++ b/lib/generators/graphql/mutation_generator.rb
@@ -7,8 +7,13 @@ module Graphql
module Generators
# TODO: What other options should be supported?
#
- # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
- # rails g graphql:mutation CreatePostMutation
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Schema::RelayClassicMutation` by name**
+ #
+ # ```ruby
+ # rails g graphql:mutation CreatePostMutation
+ # ```
class MutationGenerator < Rails::Generators::NamedBase
include Core
diff --git a/lib/generators/graphql/mutation_update_generator.rb b/lib/generators/graphql/mutation_update_generator.rb
index 6200dcc570a..67193255f09 100644
--- a/lib/generators/graphql/mutation_update_generator.rb
+++ b/lib/generators/graphql/mutation_update_generator.rb
@@ -5,8 +5,13 @@ module Graphql
module Generators
# TODO: What other options should be supported?
#
- # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
- # rails g graphql:mutation UpdatePostMutation
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Schema::RelayClassicMutation` by name**
+ #
+ # ```ruby
+ # rails g graphql:mutation UpdatePostMutation
+ # ```
class MutationUpdateGenerator < OrmMutationsBase
desc "Scaffold a Relay Classic ORM update mutation for the given model class"
diff --git a/lib/generators/graphql/orm_mutations_base.rb b/lib/generators/graphql/orm_mutations_base.rb
index 74a35d163fb..87a6ed64397 100644
--- a/lib/generators/graphql/orm_mutations_base.rb
+++ b/lib/generators/graphql/orm_mutations_base.rb
@@ -7,8 +7,13 @@ module Graphql
module Generators
# TODO: What other options should be supported?
#
- # @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
- # rails g graphql:mutation CreatePostMutation
+ # **Examples**
+ #
+ # **Example: Generate a `GraphQL::Schema::RelayClassicMutation` by name**
+ #
+ # ```ruby
+ # rails g graphql:mutation CreatePostMutation
+ # ```
class OrmMutationsBase < Rails::Generators::NamedBase
include Core
include Rails::Generators::ResourceHelpers
diff --git a/lib/generators/graphql/type_generator.rb b/lib/generators/graphql/type_generator.rb
index 55f207c532f..b08200ac511 100644
--- a/lib/generators/graphql/type_generator.rb
+++ b/lib/generators/graphql/type_generator.rb
@@ -34,10 +34,19 @@ def create_type_file
# Take a type expression in any combination of GraphQL or Ruby styles
# and return it in a specified output style
# TODO: nullability / list with `mode: :graphql` doesn't work
- # @param type_expresson [String]
- # @param mode [Symbol]
- # @param null [Boolean]
- # @return [(String, Boolean)] The type expression, followed by `null:` value
+ #
+ # **Parameters**
+ #
+ # - `type_expresson` (`String`)
+ # - `mode` (`Symbol`)
+ # - `null` (`Boolean`)
+ #
+ # **Returns**
+ #
+ # - `(String, Boolean)` — The type expression, followed by `null:` value
+ #
+ # :call-seq:
+ # normalize_type_expression(type_expression, Symbol mode:, bool null:) -> (String, bool)
def self.normalize_type_expression(type_expression, mode:, null: true)
if type_expression.start_with?("!")
normalize_type_expression(type_expression[1..-1], mode: mode, null: false)
@@ -73,22 +82,42 @@ def self.normalize_type_expression(type_expression, mode:, null: true)
private
- # @return [String] The user-provided type name, normalized to Ruby code
+ # **Returns**
+ #
+ # - `String` — The user-provided type name, normalized to Ruby code
+ #
+ # :call-seq:
+ # type_ruby_name() -> String
def type_ruby_name
@type_ruby_name ||= self.class.normalize_type_expression(name, mode: :ruby)[0]
end
- # @return [String] The user-provided type name, as a GraphQL name
+ # **Returns**
+ #
+ # - `String` — The user-provided type name, as a GraphQL name
+ #
+ # :call-seq:
+ # type_graphql_name() -> String
def type_graphql_name
@type_graphql_name ||= self.class.normalize_type_expression(name, mode: :graphql)[0]
end
- # @return [String] The user-provided type name, as a file name (without extension)
+ # **Returns**
+ #
+ # - `String` — The user-provided type name, as a file name (without extension)
+ #
+ # :call-seq:
+ # type_file_name() -> String
def type_file_name
@type_file_name ||= "#{type_graphql_name}Type".underscore
end
- # @return [Array] User-provided fields, in `(name, Ruby type name)` pairs
+ # **Returns**
+ #
+ # - `Array` — User-provided fields, in `(name, Ruby type name)` pairs
+ #
+ # :call-seq:
+ # normalized_fields() -> Array[NormalizedField]
def normalized_fields
@normalized_fields ||= fields.map { |f|
name, raw_type = f.split(":", 2)
diff --git a/lib/graphql.rb b/lib/graphql.rb
index 110a40a54d7..73928e6e8f6 100644
--- a/lib/graphql.rb
+++ b/lib/graphql.rb
@@ -11,6 +11,9 @@ module GraphQL
extend Autoload
# Load all `autoload`-configured classes, and also eager-load dependents who have autoloads of their own.
+ #
+ # This is useful during application boot when autoloading is disabled or
+ # when a framework needs to eager-load its namespaces.
def self.eager_load!
super
Query.eager_load!
@@ -36,6 +39,14 @@ class RequiredImplementationMissingError < Error
end
class << self
+ # Get the parser used by `GraphQL.parse` and `GraphQL.parse_file`.
+ #
+ # **Returns**
+ #
+ # - `Class` — the configured parser class
+ #
+ # :call-seq:
+ # default_parser() -> Class
def default_parser
@default_parser ||= GraphQL::Language::Parser
end
@@ -44,21 +55,44 @@ def default_parser
end
# Turn a query string or schema definition into an AST
- # @param graphql_string [String] a GraphQL query string or schema definition
- # @return [GraphQL::Language::Nodes::Document]
+ #
+ # **Parameters**
+ #
+ # - `graphql_string` (`String`) — a GraphQL query string or schema definition
+ #
+ # **Returns**
+ #
+ # - `GraphQL::Language::Nodes::Document`
+ #
+ # :call-seq:
+ # parse(String graphql_string, trace:, filename:, max_tokens:) -> GraphQL::Language::Nodes::Document
def self.parse(graphql_string, trace: GraphQL::Tracing::NullTrace, filename: nil, max_tokens: nil)
default_parser.parse(graphql_string, trace: trace, filename: filename, max_tokens: max_tokens)
end
# Read the contents of `filename` and parse them as GraphQL
- # @param filename [String] Path to a `.graphql` file containing IDL or query
- # @return [GraphQL::Language::Nodes::Document]
+ #
+ # **Parameters**
+ #
+ # - `filename` (`String`) — Path to a `.graphql` file containing IDL or query
+ #
+ # **Returns**
+ #
+ # - `GraphQL::Language::Nodes::Document`
+ #
+ # :call-seq:
+ # parse_file(String filename) -> GraphQL::Language::Nodes::Document
def self.parse_file(filename)
content = File.read(filename)
default_parser.parse(content, filename: filename)
end
- # @return [Array]
+ # **Returns**
+ #
+ # - `Array`
+ #
+ # :call-seq:
+ # scan(graphql_string) -> Array[Array]
def self.scan(graphql_string)
default_parser.scan(graphql_string)
end
diff --git a/lib/graphql/analysis.rb b/lib/graphql/analysis.rb
index 36f14019f8f..2e1d6f95b6d 100644
--- a/lib/graphql/analysis.rb
+++ b/lib/graphql/analysis.rb
@@ -21,9 +21,17 @@ def initialize(...)
# Multiplex analyzers are ran for all queries, keeping state.
# Query analyzers are ran per query, without carrying state between queries.
#
- # @param multiplex [GraphQL::Execution::Multiplex]
- # @param analyzers [Array]
- # @return [Array] Results from multiplex analyzers
+ # **Parameters**
+ #
+ # - `multiplex` (`GraphQL::Execution::Multiplex`)
+ # - `analyzers` (`Array`)
+ #
+ # **Returns**
+ #
+ # - `Array` — Results from multiplex analyzers
+ #
+ # :call-seq:
+ # analyze_multiplex(GraphQL::Execution::Multiplex multiplex, Array[GraphQL::Analysis::Analyzer] analyzers) -> Array[Any]
def analyze_multiplex(multiplex, analyzers)
multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
@@ -50,9 +58,17 @@ def analyze_multiplex(multiplex, analyzers)
end
end
- # @param query [GraphQL::Query]
- # @param analyzers [Array]
- # @return [Array] Results from those analyzers
+ # **Parameters**
+ #
+ # - `query` (`GraphQL::Query`)
+ # - `analyzers` (`Array`)
+ #
+ # **Returns**
+ #
+ # - `Array` — Results from those analyzers
+ #
+ # :call-seq:
+ # analyze_query(GraphQL::Query query, Array[GraphQL::Analysis::Analyzer] analyzers, multiplex_analyzers:) -> Array[Any]
def analyze_query(query, analyzers, multiplex_analyzers: [])
query.current_trace.analyze_query(query: query) do
query_analyzers = analyzers.map { |analyzer| analyzer.new(query) }
diff --git a/lib/graphql/analysis/analyzer.rb b/lib/graphql/analysis/analyzer.rb
index ab9943d51d4..10ff3a18606 100644
--- a/lib/graphql/analysis/analyzer.rb
+++ b/lib/graphql/analysis/analyzer.rb
@@ -7,7 +7,9 @@ module Analysis
# When an analyzer is initialized with a Multiplex, you can always get the current query from
# `visitor.query` in the visit methods.
#
- # @param [GraphQL::Query, GraphQL::Execution::Multiplex] The query or multiplex to analyze
+ # **Parameters**
+ #
+ # - `The` (`GraphQL::Query, GraphQL::Execution::Multiplex`) — query or multiplex to analyze
class Analyzer
def initialize(subject)
@subject = subject
@@ -23,21 +25,39 @@ def initialize(subject)
# Analyzer hook to decide at analysis time whether a query should
# be analyzed or not.
- # @return [Boolean] If the query should be analyzed or not
+ #
+ # **Returns**
+ #
+ # - `Boolean` — If the query should be analyzed or not
+ #
+ # :call-seq:
+ # analyze?() -> bool
def analyze?
true
end
# Analyzer hook to decide at analysis time whether analysis
# requires a visitor pass; can be disabled for precomputed results.
- # @return [Boolean] If analysis requires visitation or not
+ #
+ # **Returns**
+ #
+ # - `Boolean` — If analysis requires visitation or not
+ #
+ # :call-seq:
+ # visit?() -> bool
def visit?
true
end
- # The result for this analyzer. Returning {GraphQL::AnalysisError} results
+ # The result for this analyzer. Returning [GraphQL::AnalysisError](rdoc-ref:GraphQL::AnalysisError) results
# in a query error.
- # @return [Any] The analyzer result
+ #
+ # **Returns**
+ #
+ # - `Any` — The analyzer result
+ #
+ # :call-seq:
+ # result() -> Any
def result
raise GraphQL::RequiredImplementationMissingError
end
@@ -76,14 +96,28 @@ def on_leave_#{member_name}(node, parent, visitor)
# rubocop:enable Development/NoEvalCop
protected
- # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
+ # **Returns**
+ #
+ # - `GraphQL::Query, GraphQL::Execution::Multiplex` — Whatever this analyzer is analyzing
+ #
+ # :call-seq:
+ # subject -> GraphQL::Query | GraphQL::Execution::Multiplex
attr_reader :subject
- # @return [GraphQL::Query, nil] `nil` if this analyzer is visiting a multiplex
- # (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
+ # **Returns**
+ #
+ # - `GraphQL::Query, nil` — `nil` if this analyzer is visiting a multiplex (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
+ #
+ # :call-seq:
+ # query -> GraphQL::Query | nil
attr_reader :query
- # @return [GraphQL::Execution::Multiplex, nil] `nil` if this analyzer is visiting a query
+ # **Returns**
+ #
+ # - `GraphQL::Execution::Multiplex, nil` — `nil` if this analyzer is visiting a query
+ #
+ # :call-seq:
+ # multiplex -> GraphQL::Execution::Multiplex | nil
attr_reader :multiplex
end
end
diff --git a/lib/graphql/analysis/query_complexity.rb b/lib/graphql/analysis/query_complexity.rb
index 9afd19f728e..b0b09e56071 100644
--- a/lib/graphql/analysis/query_complexity.rb
+++ b/lib/graphql/analysis/query_complexity.rb
@@ -51,11 +51,19 @@ class ScopedTypeComplexity < Hash
attr_reader :field_definition, :response_path, :query
- # @param parent_type [Class] The owner of `field_definition`
- # @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
- # @param query [GraphQL::Query] Used for `query.possible_types`
- # @param response_path [Array] The path to the response key for the field
- # @return [Hash>]
+ # **Parameters**
+ #
+ # - `parent_type` (`Class`) — The owner of `field_definition`
+ # - `field_definition` (`GraphQL::Field, GraphQL::Schema::Field`) — Used for getting the `.complexity` configuration
+ # - `query` (`GraphQL::Query`) — Used for `query.possible_types`
+ # - `response_path` (`Array`) — The path to the response key for the field
+ #
+ # **Returns**
+ #
+ # - `Hash>`
+ #
+ # :call-seq:
+ # initialize(Class parent_type, GraphQL::Field | GraphQL::Schema::Field field_definition, GraphQL::Query query, Array[String] response_path) -> Hash[GraphQL::BaseType, Hash[String, ScopedTypeComplexity]]
def initialize(parent_type, field_definition, query, response_path)
super(&DEFAULT_PROC)
@parent_type = parent_type
@@ -65,7 +73,12 @@ def initialize(parent_type, field_definition, query, response_path)
@nodes = []
end
- # @return [Array]
+ # **Returns**
+ #
+ # - `Array`
+ #
+ # :call-seq:
+ # nodes -> Array[GraphQL::Language::Nodes::Field]
attr_reader :nodes
def own_complexity(child_complexity)
@@ -107,17 +120,30 @@ def on_leave_field(node, parent, visitor)
private
- # @return [Integer]
+ # **Returns**
+ #
+ # - `Integer`
+ #
+ # :call-seq:
+ # max_possible_complexity(mode:) -> Integer
def max_possible_complexity(mode: :future)
@complexities_on_type_by_query.reduce(0) do |total, (query, scopes_stack)|
total + merged_max_complexity_for_scopes(query, [scopes_stack.first], mode)
end
end
- # @param query [GraphQL::Query] Used for `query.possible_types`
- # @param scopes [Array] Array of scoped type complexities
- # @param mode [:future, :legacy]
- # @return [Integer]
+ # **Parameters**
+ #
+ # - `query` (`GraphQL::Query`) — Used for `query.possible_types`
+ # - `scopes` (`Array`) — Array of scoped type complexities
+ # - `mode` (`:future, :legacy`)
+ #
+ # **Returns**
+ #
+ # - `Integer`
+ #
+ # :call-seq:
+ # merged_max_complexity_for_scopes(GraphQL::Query query, Array[ScopedTypeComplexity] scopes, :future | :legacy mode) -> Integer
def merged_max_complexity_for_scopes(query, scopes, mode)
# Aggregate a set of all possible scope types encountered (scope keys).
# Use a hash, but ignore the values; it's just a fast way to work with the keys.
@@ -182,14 +208,27 @@ def types_intersect?(query, a, b)
# A hook which is called whenever a field's max complexity is calculated.
# Override this method to capture individual field complexity details.
#
- # @param scoped_type_complexity [ScopedTypeComplexity]
- # @param max_complexity [Numeric] Field's maximum complexity including child complexity
- # @param child_complexity [Numeric, nil] Field's child complexity
+ # **Parameters**
+ #
+ # - `scoped_type_complexity` (`ScopedTypeComplexity`)
+ # - `max_complexity` (`Numeric`) — Field's maximum complexity including child complexity
+ # - `child_complexity` (`Numeric, nil`) — Field's child complexity
+ #
+ # :call-seq:
+ # field_complexity(ScopedTypeComplexity scoped_type_complexity, Numeric max_complexity:, Numeric | nil child_complexity:)
def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
end
- # @param inner_selections [Array>] Field selections for a scope
- # @return [Integer] Total complexity value for all these selections in the parent scope
+ # **Parameters**
+ #
+ # - `inner_selections` (`Array>`) — Field selections for a scope
+ #
+ # **Returns**
+ #
+ # - `Integer` — Total complexity value for all these selections in the parent scope
+ #
+ # :call-seq:
+ # merged_max_complexity(query, Array[Hash[String, ScopedTypeComplexity]] inner_selections) -> Integer
def merged_max_complexity(query, inner_selections)
child_scopes_by_key = {}
inner_selections.each do |inner_selection|
diff --git a/lib/graphql/analysis/query_depth.rb b/lib/graphql/analysis/query_depth.rb
index b6859bb119e..31c1817e078 100644
--- a/lib/graphql/analysis/query_depth.rb
+++ b/lib/graphql/analysis/query_depth.rb
@@ -5,24 +5,28 @@ module Analysis
#
# See https://graphql-ruby.org/queries/ast_analysis.html for more examples.
#
- # @example Logging the depth of a query
- # class LogQueryDepth < GraphQL::Analysis::QueryDepth
- # def result
- # log("GraphQL query depth: #{@max_depth}")
- # end
- # end
+ # **Examples**
#
- # # In your Schema file:
+ # **Example: Logging the depth of a query**
#
- # class MySchema < GraphQL::Schema
- # query_analyzer LogQueryDepth
+ # ```ruby
+ # class LogQueryDepth < GraphQL::Analysis::QueryDepth
+ # def result
+ # log("GraphQL query depth: #{@max_depth}")
# end
+ # end
+ #
+ # # In your Schema file:
#
- # # When you run the query, the depth will get logged:
+ # class MySchema < GraphQL::Schema
+ # query_analyzer LogQueryDepth
+ # end
#
- # Schema.execute(query_str)
- # # GraphQL query depth: 8
+ # # When you run the query, the depth will get logged:
#
+ # Schema.execute(query_str)
+ # # GraphQL query depth: 8
+ # ```
class QueryDepth < Analyzer
def initialize(query)
@max_depth = 0
diff --git a/lib/graphql/analysis/visitor.rb b/lib/graphql/analysis/visitor.rb
index 4e1d96bcdc2..7ab89374054 100644
--- a/lib/graphql/analysis/visitor.rb
+++ b/lib/graphql/analysis/visitor.rb
@@ -8,7 +8,7 @@ module Analysis
# only the selected operation, providing helpers for common use cases such
# as skipped fields and visiting fragment spreads.
#
- # @see {GraphQL::Analysis::Analyzer} AST Analyzers for queries
+ # See [GraphQL::Analysis::Analyzer](rdoc-ref:GraphQL::Analysis::Analyzer) AST Analyzers for queries
class Visitor < GraphQL::Language::StaticVisitor
def initialize(query:, analyzers:, timeout:)
@analyzers = analyzers
@@ -32,13 +32,28 @@ def initialize(query:, analyzers:, timeout:)
super(query.selected_operation)
end
- # @return [GraphQL::Query] the query being visited
+ # **Returns**
+ #
+ # - `GraphQL::Query` — the query being visited
+ #
+ # :call-seq:
+ # query -> GraphQL::Query
attr_reader :query
- # @return [Array] Types whose scope we've entered
+ # **Returns**
+ #
+ # - `Array` — Types whose scope we've entered
+ #
+ # :call-seq:
+ # object_types -> Array[GraphQL::ObjectType]
attr_reader :object_types
- # @return [Array` — Array of errors rescued during analysis
+ #
+ # :call-seq:
+ # rescued_errors -> Array[GraphQL::AnalysisError]
attr_reader :rescued_errors
def visit
@@ -48,23 +63,44 @@ def visit
# Visit Helpers
- # @return [GraphQL::Execution::Interpreter::Arguments] Arguments for this node, merging default values, literal values and query variables
- # @see {GraphQL::Query#arguments_for}
+ # See [GraphQL::Query#arguments_for](rdoc-ref:GraphQL::Query#arguments_for)
+ #
+ # **Returns**
+ #
+ # - `GraphQL::Execution::Interpreter::Arguments` — Arguments for this node, merging default values, literal values and query variables
+ #
+ # :call-seq:
+ # arguments_for(ast_node, field_definition) -> GraphQL::Execution::Interpreter::Arguments
def arguments_for(ast_node, field_definition)
@query.arguments_for(ast_node, field_definition)
end
- # @return [Boolean] If the visitor is currently inside a fragment definition
+ # **Returns**
+ #
+ # - `Boolean` — If the visitor is currently inside a fragment definition
+ #
+ # :call-seq:
+ # visiting_fragment_definition?() -> bool
def visiting_fragment_definition?
@in_fragment_def
end
- # @return [Boolean] If the current node should be skipped because of a skip or include directive
+ # **Returns**
+ #
+ # - `Boolean` — If the current node should be skipped because of a skip or include directive
+ #
+ # :call-seq:
+ # skipping?() -> bool
def skipping?
@skipping
end
- # @return [Array] The path to the response key for the current field
+ # **Returns**
+ #
+ # - `Array` — The path to the response key for the current field
+ #
+ # :call-seq:
+ # response_path() -> Array[String]
def response_path
@response_path.dup
end
@@ -206,37 +242,72 @@ def on_fragment_spread(node, parent)
@path.pop
end
- # @return [GraphQL::BaseType] The current object type
+ # **Returns**
+ #
+ # - `GraphQL::BaseType` — The current object type
+ #
+ # :call-seq:
+ # type_definition() -> GraphQL::BaseType
def type_definition
@object_types.last
end
- # @return [GraphQL::BaseType] The type which the current type came from
+ # **Returns**
+ #
+ # - `GraphQL::BaseType` — The type which the current type came from
+ #
+ # :call-seq:
+ # parent_type_definition() -> GraphQL::BaseType
def parent_type_definition
@object_types[-2]
end
- # @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
+ # **Returns**
+ #
+ # - `GraphQL::Field, nil` — The most-recently-entered GraphQL::Field, if currently inside one
+ #
+ # :call-seq:
+ # field_definition() -> GraphQL::Field | nil
def field_definition
@field_definitions.last
end
- # @return [GraphQL::Field, nil] The GraphQL field which returned the object that the current field belongs to
+ # **Returns**
+ #
+ # - `GraphQL::Field, nil` — The GraphQL field which returned the object that the current field belongs to
+ #
+ # :call-seq:
+ # previous_field_definition() -> GraphQL::Field | nil
def previous_field_definition
@field_definitions[-2]
end
- # @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
+ # **Returns**
+ #
+ # - `GraphQL::Directive, nil` — The most-recently-entered GraphQL::Directive, if currently inside one
+ #
+ # :call-seq:
+ # directive_definition() -> GraphQL::Directive | nil
def directive_definition
@directive_definitions.last
end
- # @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
+ # **Returns**
+ #
+ # - `GraphQL::Argument, nil` — The most-recently-entered GraphQL::Argument, if currently inside one
+ #
+ # :call-seq:
+ # argument_definition() -> GraphQL::Argument | nil
def argument_definition
@argument_definitions.last
end
- # @return [GraphQL::Argument, nil] The previous GraphQL argument
+ # **Returns**
+ #
+ # - `GraphQL::Argument, nil` — The previous GraphQL argument
+ #
+ # :call-seq:
+ # previous_argument_definition() -> GraphQL::Argument | nil
def previous_argument_definition
@argument_definitions[-2]
end
diff --git a/lib/graphql/autoload.rb b/lib/graphql/autoload.rb
index 82aa538cfc4..4ba81a72026 100644
--- a/lib/graphql/autoload.rb
+++ b/lib/graphql/autoload.rb
@@ -1,13 +1,22 @@
# frozen_string_literal: true
module GraphQL
- # @see GraphQL::Railtie for automatic Rails integration
+ # See [GraphQL::Railtie](rdoc-ref:GraphQL::Railtie) for automatic Rails integration
module Autoload
# Register a constant named `const_name` to be loaded from `path`.
- # This is like `Kernel#autoload` but it tracks the constants so they can be eager-loaded with {#eager_load!}
- # @param const_name [Symbol]
- # @param path [String]
- # @return [void]
+ # This is like `Kernel#autoload` but it tracks the constants so they can be eager-loaded with [eager load!](rdoc-ref:#eager_load!)
+ #
+ # **Parameters**
+ #
+ # - `const_name` (`Symbol`)
+ # - `path` (`String`)
+ #
+ # **Returns**
+ #
+ # - `void`
+ #
+ # :call-seq:
+ # autoload(Symbol const_name, String path) -> void
def autoload(const_name, path)
@_eagerloaded_constants ||= []
@_eagerloaded_constants << const_name
@@ -16,7 +25,13 @@ def autoload(const_name, path)
end
# Call this to load this constant's `autoload` dependents and continue calling recursively
- # @return [void]
+ #
+ # **Returns**
+ #
+ # - `void`
+ #
+ # :call-seq:
+ # eager_load!() -> void
def eager_load!
@_eager_loading = true
if @_eagerloaded_constants
@@ -30,7 +45,12 @@ def eager_load!
private
- # @return [Boolean] `true` if GraphQL-Ruby is currently eager-loading its constants
+ # **Returns**
+ #
+ # - `Boolean` — `true` if GraphQL-Ruby is currently eager-loading its constants
+ #
+ # :call-seq:
+ # eager_loading?() -> bool
def eager_loading?
@_eager_loading ||= false
end
diff --git a/lib/graphql/backtrace.rb b/lib/graphql/backtrace.rb
index c97543d1fe0..17a55b152d8 100644
--- a/lib/graphql/backtrace.rb
+++ b/lib/graphql/backtrace.rb
@@ -2,18 +2,22 @@
require "graphql/backtrace/table"
require "graphql/backtrace/traced_error"
module GraphQL
- # Wrap unhandled errors with {TracedError}.
+ # Wrap unhandled errors with [TracedError](rdoc-ref:TracedError).
#
- # {TracedError} provides a GraphQL backtrace with arguments and return values.
- # The underlying error is available as {TracedError#cause}.
+ # [TracedError](rdoc-ref:TracedError) provides a GraphQL backtrace with arguments and return values.
+ # The underlying error is available as `TracedError#cause`.
#
- # @example toggling backtrace annotation
- # class MySchema < GraphQL::Schema
- # if Rails.env.development? || Rails.env.test?
- # use GraphQL::Backtrace
- # end
- # end
+ # **Examples**
+ #
+ # **Example: toggling backtrace annotation**
#
+ # ```ruby
+ # class MySchema < GraphQL::Schema
+ # if Rails.env.development? || Rails.env.test?
+ # use GraphQL::Backtrace
+ # end
+ # end
+ # ```
class Backtrace
include Enumerable
extend Forwardable
diff --git a/lib/graphql/backtrace/table.rb b/lib/graphql/backtrace/table.rb
index 04a60769d59..2890342b449 100644
--- a/lib/graphql/backtrace/table.rb
+++ b/lib/graphql/backtrace/table.rb
@@ -18,12 +18,22 @@ def initialize(context, value:)
@override_value = value
end
- # @return [String] A table layout of backtrace with metadata
+ # **Returns**
+ #
+ # - `String` — A table layout of backtrace with metadata
+ #
+ # :call-seq:
+ # to_table() -> String
def to_table
@to_table ||= render_table(rows)
end
- # @return [Array] An array of position + field name entries
+ # **Returns**
+ #
+ # - `Array` — An array of position + field name entries
+ #
+ # :call-seq:
+ # to_backtrace() -> Array[String]
def to_backtrace
@to_backtrace ||= begin
backtrace = rows.map { |r| "#{r[0]}: #{r[1]}" }
@@ -134,7 +144,12 @@ def find_ast_node(node, last_part)
nil
end
- # @return [String]
+ # **Returns**
+ #
+ # - `String`
+ #
+ # :call-seq:
+ # render_table(rows) -> String
def render_table(rows)
max = Array.new(HEADERS.length, MIN_COL_WIDTH)
diff --git a/lib/graphql/backtrace/traced_error.rb b/lib/graphql/backtrace/traced_error.rb
index caa7c7d7311..0bfc2a935f7 100644
--- a/lib/graphql/backtrace/traced_error.rb
+++ b/lib/graphql/backtrace/traced_error.rb
@@ -3,10 +3,20 @@ module GraphQL
class Backtrace
# When {Backtrace} is enabled, raised errors are wrapped with {TracedError}.
class TracedError < GraphQL::Error
- # @return [Array] Printable backtrace of GraphQL error context
+ # **Returns**
+ #
+ # - `Array` — Printable backtrace of GraphQL error context
+ #
+ # :call-seq:
+ # graphql_backtrace -> Array[String]
attr_reader :graphql_backtrace
- # @return [GraphQL::Query::Context] The context at the field where the error was raised
+ # **Returns**
+ #
+ # - `GraphQL::Query::Context` — The context at the field where the error was raised
+ #
+ # :call-seq:
+ # context -> GraphQL::Query::Context
attr_reader :context
MESSAGE_TEMPLATE = <<-MESSAGE
diff --git a/lib/graphql/current.rb b/lib/graphql/current.rb
index 5d5bbe08636..fafb5a71e1f 100644
--- a/lib/graphql/current.rb
+++ b/lib/graphql/current.rb
@@ -5,24 +5,32 @@ module GraphQL
#
# It won't work across unrelated fibers, although it will work in child Fibers.
#
- # @example Setting Up ActiveRecord::QueryLogs
+ # **Examples**
#
- # config.active_record.query_log_tags = [
- # :namespaced_controller,
- # :action,
- # :job,
- # # ...
- # {
- # # GraphQL runtime info:
- # current_graphql_operation: -> { GraphQL::Current.operation_name },
- # current_graphql_field: -> { GraphQL::Current.field&.path },
- # current_dataloader_source: -> { GraphQL::Current.dataloader_source_class },
- # # ...
- # },
- # ]
+ # **Example: Setting Up ActiveRecord::QueryLogs**
#
+ # ```ruby
+ # config.active_record.query_log_tags = [
+ # :namespaced_controller,
+ # :action,
+ # :job,
+ # # ...
+ # {
+ # # GraphQL runtime info:
+ # current_graphql_operation: -> { GraphQL::Current.operation_name },
+ # current_graphql_field: -> { GraphQL::Current.field&.path },
+ # current_dataloader_source: -> { GraphQL::Current.dataloader_source_class },
+ # # ...
+ # },
+ # ]
+ # ```
module Current
- # @return [String, nil] Comma-joined operation names for the currently-running {Execution::Multiplex}. `nil` if all operations are anonymous.
+ # **Returns**
+ #
+ # - `String, nil` — Comma-joined operation names for the currently-running `Execution::Multiplex`. `nil` if all operations are anonymous.
+ #
+ # :call-seq:
+ # operation_name() -> String | nil
def self.operation_name
if (m = Fiber[:__graphql_current_multiplex])
m.context[:__graphql_current_operation_name] ||= begin
@@ -38,8 +46,14 @@ def self.operation_name
end
end
- # @see GraphQL::Field#path for a string identifying this field
- # @return [GraphQL::Field, nil] The currently-running field, if there is one.
+ # See [Schema::Member::HasPath#path](rdoc-ref:GraphQL::Schema::Member::HasPath#path) for a string identifying this field
+ #
+ # **Returns**
+ #
+ # - `GraphQL::Field, nil` — The currently-running field, if there is one.
+ #
+ # :call-seq:
+ # field() -> GraphQL::Field | nil
def self.field
if (interpreter_info = Fiber[:__graphql_runtime_info])
interpreter_info.values&.first&.current_field
@@ -50,12 +64,22 @@ def self.field
end
end
- # @return [Class, nil] The currently-running {Dataloader::Source} class, if there is one.
+ # **Returns**
+ #
+ # - `Class, nil` — The currently-running [Dataloader::Source](rdoc-ref:Dataloader::Source) class, if there is one.
+ #
+ # :call-seq:
+ # dataloader_source_class() -> Class | nil
def self.dataloader_source_class
Fiber[:__graphql_current_dataloader_source]&.class
end
- # @return [GraphQL::Dataloader::Source, nil] The currently-running source, if there is one
+ # **Returns**
+ #
+ # - `GraphQL::Dataloader::Source, nil` — The currently-running source, if there is one
+ #
+ # :call-seq:
+ # dataloader_source() -> GraphQL::Dataloader::Source | nil
def self.dataloader_source
Fiber[:__graphql_current_dataloader_source]
end
diff --git a/lib/graphql/dashboard.rb b/lib/graphql/dashboard.rb
index 05a26657ee9..cfa1d0e5a8e 100644
--- a/lib/graphql/dashboard.rb
+++ b/lib/graphql/dashboard.rb
@@ -5,36 +5,49 @@ module Graphql
# `GraphQL::Dashboard` is a `Rails::Engine`-based dashboard for viewing metadata about your GraphQL schema.
#
# Pass the class name of your schema when mounting it.
- # @see GraphQL::Tracing::DetailedTrace DetailedTrace for viewing production traces in the Dashboard
+ # See [GraphQL::Tracing::DetailedTrace](rdoc-ref:GraphQL::Tracing::DetailedTrace) DetailedTrace for viewing production traces in the Dashboard
#
- # @example Mounting the Dashboard in your app
- # mount GraphQL::Dashboard, at: "graphql_dashboard", schema: "MySchema"
+ # **Examples**
#
- # Pass an array to allow selecting from multiple schemas with the `schema` query parameter.
- # mount GraphQL::Dashboard, at: "graphql_dashboard", schema: ["MySchema", "OtherSchema"]
+ # **Example: Mounting the Dashboard in your app**
#
- # @example Authenticating the Dashboard with HTTP Basic Auth
- # # config/initializers/graphql_dashboard.rb
- # GraphQL::Dashboard.middleware.use(Rack::Auth::Basic) do |username, password|
- # # Compare the provided username/password to an application setting:
- # ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.graphql_dashboard_username, username) &&
- # ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.graphql_dashboard_username, password)
- # end
+ # ```ruby
+ # mount GraphQL::Dashboard, at: "graphql_dashboard", schema: "MySchema"
+ # ```
+ #
+ # To allow selecting from multiple schemas with the `schema` query parameter:
+ #
+ # ```ruby
+ # mount GraphQL::Dashboard, at: "graphql_dashboard", schema: ["MySchema", "OtherSchema"]
+ # ```
#
- # @example Custom Rails authentication
- # # config/initializers/graphql_dashboard.rb
- # ActiveSupport.on_load(:graphql_dashboard_application_controller) do
- # # context here is GraphQL::Dashboard::ApplicationController
+ # **Example: Authenticating the Dashboard with HTTP Basic Auth**
#
- # before_action do
- # raise ActionController::RoutingError.new('Not Found') unless current_user&.admin?
- # end
+ # ```ruby
+ # # config/initializers/graphql_dashboard.rb
+ # GraphQL::Dashboard.middleware.use(Rack::Auth::Basic) do |username, password|
+ # # Compare the provided username/password to an application setting:
+ # ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.graphql_dashboard_username, username) &&
+ # ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.graphql_dashboard_username, password)
+ # end
+ # ```
#
- # def current_user
- # # load current user
- # end
+ # **Example: Custom Rails authentication**
+ #
+ # ```ruby
+ # # config/initializers/graphql_dashboard.rb
+ # ActiveSupport.on_load(:graphql_dashboard_application_controller) do
+ # # context here is GraphQL::Dashboard::ApplicationController
+ #
+ # before_action do
+ # raise ActionController::RoutingError.new('Not Found') unless current_user&.admin?
# end
#
+ # def current_user
+ # # load current user
+ # end
+ # end
+ # ```
class Dashboard < Rails::Engine
engine_name "graphql_dashboard"
isolate_namespace(Graphql::Dashboard)
diff --git a/lib/graphql/dataloader.rb b/lib/graphql/dataloader.rb
index f58209995b9..df31696d838 100644
--- a/lib/graphql/dataloader.rb
+++ b/lib/graphql/dataloader.rb
@@ -8,22 +8,27 @@
require "graphql/dataloader/active_record_source"
module GraphQL
- # This plugin supports Fiber-based concurrency, along with {GraphQL::Dataloader::Source}.
+ # This plugin supports Fiber-based concurrency, along with [GraphQL::Dataloader::Source](rdoc-ref:GraphQL::Dataloader::Source).
#
- # @example Installing Dataloader
+ # **Examples**
#
- # class MySchema < GraphQL::Schema
- # use GraphQL::Dataloader
- # end
+ # **Example: Installing Dataloader**
#
- # @example Waiting for batch-loaded data in a GraphQL field
+ # ```ruby
+ # class MySchema < GraphQL::Schema
+ # use GraphQL::Dataloader
+ # end
+ # ```
#
- # field :team, Types::Team, null: true
+ # **Example: Waiting for batch-loaded data in a GraphQL field**
#
- # def team
- # dataloader.with(Sources::Record, Team).load(object.team_id)
- # end
+ # ```ruby
+ # field :team, Types::Team, null: true
#
+ # def team
+ # dataloader.with(Sources::Record, Team).load(object.team_id)
+ # end
+ # ```
class Dataloader
class << self
attr_accessor :default_nonblocking, :default_fiber_limit
@@ -69,7 +74,12 @@ def initialize(nonblocking: self.class.default_nonblocking, fiber_limit: self.cl
@lazies_at_depth = Hash.new { |h, k| h[k] = [] }
end
- # @return [Integer, nil]
+ # **Returns**
+ #
+ # - `Integer, nil`
+ #
+ # :call-seq:
+ # fiber_limit -> Integer | nil
attr_reader :fiber_limit
def nonblocking?
@@ -79,7 +89,12 @@ def nonblocking?
# This is called before the fiber is spawned, from the parent context (i.e. from
# the thread or fiber that it is scheduled from).
#
- # @return [Hash] Current fiber-local variables
+ # **Returns**
+ #
+ # - `Hash` — Current fiber-local variables
+ #
+ # :call-seq:
+ # get_fiber_variables() -> Hash[Symbol, Object]
def get_fiber_variables
fiber_vars = {}
Thread.current.keys.each do |fiber_var_key|
@@ -92,8 +107,16 @@ def get_fiber_variables
#
# This is called within the fiber, right after it is spawned.
#
- # @param vars [Hash] Fiber-local variables from {get_fiber_variables}
- # @return [void]
+ # **Parameters**
+ #
+ # - `vars` (`Hash`) — Fiber-local variables from [get_fiber_variables](rdoc-ref:get_fiber_variables)
+ #
+ # **Returns**
+ #
+ # - `void`
+ #
+ # :call-seq:
+ # set_fiber_variables(Hash[Symbol, Object] vars) -> void
def set_fiber_variables(vars)
vars.each { |k, v| Thread.current[k] = v }
nil
@@ -106,10 +129,14 @@ def cleanup_fiber
# Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
#
- # @param source_class [Class]
- # @return [GraphQL::Dataloader::Source] An instance of {source_class}, initialized with `self, *batch_parameters`,
- # and cached for the lifetime of this {Multiplex}.
+ # **Parameters**
+ #
+ # - `source_class` (`Class`) — The source class to load
+ # - `batch_parameters` (`Array