pax_global_header 0000666 0000000 0000000 00000000064 14141214530 0014505 g ustar 00root root 0000000 0000000 52 comment=c4778ffcba5de34b05dfe1b63ce94a60201a5625
graphql-ruby-1.11.10/ 0000775 0000000 0000000 00000000000 14141214530 0014263 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/.codeclimate.yml 0000664 0000000 0000000 00000000415 14141214530 0017335 0 ustar 00root root 0000000 0000000 version: "2"
exclude_patterns:
- "spec/"
- "lib/graphql/language/lexer.rb"
- "lib/graphql/language/parser.rb"
# plugin - duplication - is failing on these
- "spec/graphql/language/printer_spec.rb"
- "lib/graphql/compatibility/query_parser_specification.rb"
graphql-ruby-1.11.10/.gitattributes 0000664 0000000 0000000 00000000064 14141214530 0017156 0 ustar 00root root 0000000 0000000 *.snap linguist-generated
*.lock linguist-generated
graphql-ruby-1.11.10/.github/ 0000775 0000000 0000000 00000000000 14141214530 0015623 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14141214530 0020006 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000003013 14141214530 0022475 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a report to help us improve graphql-ruby
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Versions**
`graphql` version:
`rails` (or other framework):
other applicable versions (`graphql-batch`, etc)
**GraphQL schema**
Include relevant types and fields (in Ruby is best, in GraphQL IDL is ok).
Are you using [interpreter](https://graphql-ruby.org/queries/interpreter.html)? Any custom instrumentation, etc?
```ruby
class Product < GraphQL::Schema::Object
field :id, ID, null: false, hash_key: :id
# …
end
class ApplicationSchema < GraphQL::Schema
query QueryType
# …
end
```
**GraphQL query**
Example GraphQL query and response (if query execution is involved)
```graphql
query {
products { id title }
}
```
```json
{
"data": {
"products": […]
}
}
```
**Steps to reproduce**
Steps to reproduce the behavior
**Expected behavior**
A clear and concise description of what you expected to happen.
**Actual behavior**
What specifically went wrong?
Place full backtrace here (if a Ruby exception is involved):
Click to view exception backtrace
```
Something went wrong
2.6.0/gems/graphql-1.9.17/lib/graphql/subscriptions/instrumentation.rb:34:in `after_query'
… don't hesitate to include all the rows here: they will be collapsed
```
**Additional context**
Add any other context about the problem here.
With these details, we can efficiently hunt down the bug!
graphql-ruby-1.11.10/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000001127 14141214530 0023534 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
graphql-ruby-1.11.10/.github/contributing.md 0000664 0000000 0000000 00000002651 14141214530 0020660 0 ustar 00root root 0000000 0000000 # Contributing
Thanks for getting involved! I hope the information below will help you contribute to graphql-ruby.
## Issues
When reporting a bug, please include these details when applicable:
- `graphql` version and other applicable versions (Rails, `graphql-batch`, etc)
- Definitions of schema or relevant types and fields (in Ruby is best, in GraphQL IDL is ok)
- Example GraphQL query and response (if query execution is involved)
- Full backtrace (if a Ruby exception is involved)
With these details, we can efficiently hunt down the bug!
## Code
It's important for code to fit in with design and maintenance goals of the project. For this reason, consider an issue to discuss new features or large refactors. That way we can work together to find suitable solution!
## Legal
By submitting a Pull Request, you disavow any rights or claims to any changes submitted to `graphql-ruby` and assign the copyright of those changes to Robert Mosolgo, the author and maintainer of `graphql-ruby`. If you cannot or don't want to reassign those rights (your employment contract for your employer may not allow this), don't submit a PR. Instead, open an issue so that someone else can give it a try.
In short, contributing code means that the code belongs to the maintainer. That's generally what you want, since the burden of upkeep, support and distribution falls on the maintainer anyways. I hope this doesn't prohibit you from contributing!
graphql-ruby-1.11.10/.github/workflows/ 0000775 0000000 0000000 00000000000 14141214530 0017660 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/.github/workflows/apidocs.yaml 0000664 0000000 0000000 00000002630 14141214530 0022167 0 ustar 00root root 0000000 0000000 name: Publish API docs
on:
# For some reason, `on: release: ...` didn't work with `nektos/act`
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
build:
name: Publish API Docs
runs-on: ubuntu-latest
steps:
- name: Checkout release tag
uses: actions/checkout@v2
with:
ref: ${{ env.GITHUB_REF }}
- name: Checkout GitHub pages branch
uses: actions/checkout@v2
with:
path: gh-pages
ref: gh-pages
- uses: actions/setup-ruby@v1
with:
ruby-version: '2.7'
- name: Bundle install
run: |
gem install bundler
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Build API docs
run: |
bundle exec rake site:fetch_latest apidocs:gen_version
- name: Commit changes as last committer
run: |
git config --global user.name rmosolgo
git config --global user.email rdmosolgo@github.com
git status
bundle exec rake site:commit_changes
git status
- name: Deploy to GitHub pages via gh-pages branch
uses: s0/git-publish-subdir-action@master
env:
REPO: self
BRANCH: gh-pages
FOLDER: gh-pages
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
graphql-ruby-1.11.10/.github/workflows/ci.yaml 0000664 0000000 0000000 00000007274 14141214530 0021151 0 ustar 00root root 0000000 0000000 name: CI Suite
on:
push
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
- run: bundle exec rake rubocop
system_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
env:
BUNDLE_GEMFILE: ./spec/dummy/Gemfile
- run: bundle exec rails test:system
working-directory: ./spec/dummy
# Some coverage goals of these tests:
# - Test once without Rails at all
# - Test postgres, to make sure that the ActiveRecord
# stuff works on that (as well as the default sqlite)
# - Test mongoid -- and several versions, since they're quite different
# - Run the tests with Rails _and_ TESTING_LEGACY=1 to test legacy codepaths
# - Run the JS unit tests once
# - Test each major version of Rails we support
# - Test the min/max minor Ruby version we support (and others?)
test:
strategy:
fail-fast: false
matrix:
include:
- gemfile: Gemfile
ruby: 2.6
- gemfile: gemfiles/rails_3.2.gemfile
ruby: 2.3
- gemfile: gemfiles/rails_4.2.gemfile
ruby: 2.4
bundler: "1"
# Rails 5.2 is tested with Postgresql below
- gemfile: gemfiles/rails_6.0.gemfile
ruby: 2.7
- gemfile: gemfiles/rails_master.gemfile
ruby: 3.0
runs-on: ubuntu-latest
steps:
- run: echo BUNDLE_GEMFILE=${{ matrix.gemfile }} > $GITHUB_ENV
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
bundler: ${{ matrix.bundler || 'default' }}
- run: bundle exec rake test
legacy_test:
runs-on: ubuntu-latest
steps:
- run: echo BUNDLE_GEMFILE='gemfiles/rails_6.0.gemfile' > $GITHUB_ENV
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake test TESTING_LEGACY=1
javascript_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake js:all
postgres_test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- run: echo BUNDLE_GEMFILE='gemfiles/rails_5.2_postgresql.gemfile' > $GITHUB_ENV
- run: echo DATABASE='POSTGRESQL' > $GITHUB_ENV
- run: echo PGPASSWORD='postgres' > $GITHUB_ENV
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake test
mongodb_test:
strategy:
fail-fast: false
matrix:
gemfile:
- gemfiles/mongoid_6.gemfile
- gemfiles/mongoid_7.gemfile
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:3.4.23
ports:
- 27017:27017
steps:
- run: echo BUNDLE_GEMFILE=${{ matrix.gemfile }} > $GITHUB_ENV
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake test
graphql-ruby-1.11.10/.github/workflows/website.yaml 0000664 0000000 0000000 00000002452 14141214530 0022211 0 ustar 00root root 0000000 0000000 name: Publish Website
on:
push:
branches: [master]
jobs:
build:
name: Publish Website
runs-on: ubuntu-latest
steps:
- name: Checkout master
uses: actions/checkout@v2
- name: Checkout GitHub pages branch
uses: actions/checkout@v2
with:
path: gh-pages
ref: gh-pages
- uses: actions/setup-ruby@v1
with:
ruby-version: '2.7'
- name: Bundle install
run: |
gem install bundler
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Build HTML, reindex
env:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
run: |
bundle exec rake site:fetch_latest site:build_doc site:update_search_index site:clean_html site:build_html
- name: Commit changes as last committer
run: |
git config --global user.name "%(git log --format="%aN" -n 1)"
git config --global user.email "%(git log --format="%aE" -n 1)"
bundle exec rake site:commit_changes
- name: Deploy to GitHub pages via gh-pages branch
uses: s0/git-publish-subdir-action@master
env:
REPO: self
BRANCH: gh-pages
FOLDER: gh-pages
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
graphql-ruby-1.11.10/.gitignore 0000664 0000000 0000000 00000000465 14141214530 0016260 0 ustar 00root root 0000000 0000000 .ruby-version
doc/
.yardoc/
guides/yardoc/
pkg/
Gemfile.lock
gemfiles/*.lock
# Test database
*.db
.bundle/
vendor/
.idea/
_site
.sass-cache
.jekyll-metadata
.jekyll-cache
gh-pages/
tmp/*
__*.db
node_modules/
yarn.lock
OperationStoreClient.js
spec/integration/tmp
.vscode/
*.swp
*.swo
javascript_client/dist/
graphql-ruby-1.11.10/.rubocop.yml 0000664 0000000 0000000 00000002075 14141214530 0016541 0 ustar 00root root 0000000 0000000 require:
- ./cop/none_without_block_cop
- ./cop/no_focus_cop
AllCops:
DisabledByDefault: true
TargetRubyVersion: 2.2
Exclude:
- 'lib/graphql/language/lexer.rb'
- 'lib/graphql/language/parser.rb'
- 'gemfiles/**/*'
- 'tmp/**/*'
- 'vendor/**/*'
- 'spec/integration/tmp/**/*'
# def ...
# end
Layout/DefEndAlignment:
EnforcedStyleAlignWith: def
# value = if
# # ...
# end
Layout/EndAlignment:
EnforcedStyleAlignWith: variable
Lint/UselessAssignment:
Enabled: true
Lint/DuplicateMethods:
Enabled: true
Metrics/ParameterLists:
Max: 7
CountKeywordArgs: false
Style/ClassAndModuleChildren:
EnforcedStyle: nested
Layout/EmptyLineBetweenDefs:
AllowAdjacentOneLineDefs: true
Style/FrozenStringLiteralComment:
Enabled: true
Layout/IndentationWidth:
Width: 2
Style/LambdaCall:
EnforcedStyle: call
Layout/LeadingCommentSpace:
Enabled: true
Naming/MethodName:
EnforcedStyle: snake_case
Style/WordArray:
EnforcedStyle: brackets
# ->(...) { ... }
Layout/SpaceInLambdaLiteral:
Enabled: true # Default is "require_no_space"
graphql-ruby-1.11.10/.yardopts 0000664 0000000 0000000 00000000162 14141214530 0016130 0 ustar 00root root 0000000 0000000 --no-private
--markup=markdown
--readme=readme.md
--title='GraphQL Ruby API Documentation'
'lib/**/*.rb' - '*.md'
graphql-ruby-1.11.10/Appraisals 0000664 0000000 0000000 00000002337 14141214530 0016312 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
appraise 'rails_3.2' do
gem 'rails', '3.2.22.5', require: 'rails/all'
gem 'activerecord', '~> 3.2.21'
gem 'actionpack', '~> 3.2.21'
gem 'test-unit'
gem 'sqlite3', "~> 1.3.6", platform: :ruby
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'sequel'
end
appraise 'rails_4.2' do
gem 'rails', '~> 4.2', require: 'rails/all'
gem 'activerecord', '~> 4.2.4'
gem 'actionpack', '~> 4.2.4'
gem 'concurrent-ruby', '1.0.0'
gem 'sqlite3', "~> 1.3.6", platform: :ruby
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'sequel'
end
appraise 'rails_5.2_postgresql' do
gem 'rails', '~> 5.2.0', require: 'rails/all'
gem 'pg', platform: :ruby
gem 'sequel'
end
appraise 'rails_6.0' do
gem 'rails', '~> 6.0.0', require: 'rails/all'
gem 'sqlite3', "~> 1.4", platform: :ruby
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'sequel'
end
appraise 'rails_master' do
gem 'rails', github: 'rails/rails', require: 'rails/all'
gem 'sqlite3', "~> 1.4", platform: :ruby
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'sequel'
end
appraise 'mongoid_7' do
gem 'mongoid', '~> 7.0.1'
end
appraise 'mongoid_6' do
gem 'mongoid', '~> 6.4.1'
end
graphql-ruby-1.11.10/CHANGELOG-pro.md 0000664 0000000 0000000 00000042674 14141214530 0016707 0 ustar 00root root 0000000 0000000 # graphql-pro
### Breaking Changes
### Deprecations
### New Features
### Bug Fix
## 1.16.2 (21 Dec 2020)
### New Features
- Subscriptions: Add `stale_ttl_s:` and `cleanup_delay_s:` to customize persistence in Redis #3252
## 1.16.1 (3 Dec 2020)
### Bug Fix
- Fix duplicate calls to `Argument#authorized?` in CanCan and Pundit integrations #3242
## 1.16.0 (10 Nov 2020)
### New Features
- Ably Subscriptions: `cipher_base:` sets up end-to-end encryption
## 1.15.7 (29 Sept 2020)
### Bug Fix
- Encoder: fix Ruby 2.7 warning #3161
- Stable connections: Handle `ARRAY[...]` selections and cursors on Postgres #3166
- Pundit: properly lookup policies for list inputs #3146
## 1.15.6 (17 Sept 2020)
### Bug Fix
- Stable Connections: Use method access to get `.cursor_#{idx}` values instead of `.attributes[:cursor_#{idx}]`, fixes #3149
## 1.15.5
### New Features
- Stable Connections: use `.to_sql` to handle orderings that use complex Arel expressions (#3109)
## 1.15.4 (28 July 2020)
### New Features
- Pundit: add `pundit_policy_class_for(object, context)` and `pundit_role_for(object, context)` for custom runtime lookups
## 1.15.3 (17 July 2020)
### Bug Fix
- Subscriptions: don't send empty updates when subscriptions return `:no_update`
## 1.15.2 (16 July 2020)
### New Features
- OperationStore: improve handling of archived operations in index views
## 1.15.1 (16 July 2020)
(Oops, bad release!)
## 1.15.0 (15 July 2020)
- OperationStore: Store & display `last_used_at` for operation store clients and operations. To upgrade, add the column to your ActiveRecord table:
```ruby
add_column :graphql_client_operations, :last_used_at, :datetime
```
(It works out-of-the-box with the Redis backend.)
You can opt out of this feature by adding `use GraphQL::Pro::OperationStore, ... default_touch_last_used_at: false` to your schema setup.
- OperationStore: Add archive/unarchive workflow for operations. To upgrade, add the column to your table:
```ruby
add_column :graphql_client_operations, :is_archived, :boolean, index: true
```
(It works out-of-the-box with the Redis backend.)
- OperationStore: Fix indexing of enum values
## 1.14.1 (29 June 2020)
- CanCan: Accept `can_can_attribute:` configuration, which is passed as the third input to `.can?(...)`
## 1.14.0 (13 June 2020)
### New Features
- Add PubnubSubscriptions
- Update subscription implementations to support `broadcast: true` when available
### Bug Fix
- More Ruby 2.7 warning fixes
## 1.13.6 (8 June 2020)
### Bug Fix
- Return the proper `pageInfo` values when it's requested before `edges` or `nodes` (#2972)
## 1.13.5 (11 May 2020)
### Bug Fix
- Fix some warnings on Ruby 2.7
## 1.13.4 (17 Apr 2020)
### Bug Fix
- StableRelationConnection: properly return `hasNextPage: true` when `before` and `max_page_size` are used.
## 1.13.3 (2 Apr 2020)
### New Features
- `GraphQL::Pro::OperationStore::Migration` can be used to copy persisted operations from one backend to another (eg, ActiveRecord to Redis). See the source file, `lib/graphql/pro/operation_store/migration.rb` for docs.
## 1.13.2 (28 Mar 2020)
### Deprecations
- `GraphQL::Pro::Subscriptions` is deprecated; use `GraphQL::Pro::PusherSubscriptions` instead which works the same, but better (see below). This new name avoids confusion with the later-added `AblySubscriptions`.
### New Features
- `GraphQL::Pro::PusherSubscriptions` replaces `GraphQL::Pro::Subscriptions` and adds orphaned record cleanup. (No more dangling records in Redis.)
## 1.13.1 (12 Mar 2020)
- Use `nonce: true` when working with cursors in new stable connections
## 1.13.0 (10 Feb 2020)
### New Features
- OperationStore supports a `redis:` backend
- OperationStore supports an arbitrary `backend_class:` for persistence operations
### Bug Fix
- Use a loop when clearing Redis subscription state to avoid large stack traces #2701
- Handle empty subscription keys when publishing updates #2061
## 1.12.2 (22 Jan 2020)
### Bug Fix
- Improve backwards compat with OperationStore (Improve adding `.tracer`, use `.graphql_name` when indexing)
## 1.12.1 (20 Jan 2020)
### Bug Fix
- Fix OperationStore on class-based schemas with query instrumenters that use the query string
## 1.12.0 (20 Jan 2020)
### Deprecations
- `GraphQL::Pro::Monitoring` is deprecated; see Tracing for a replacement: https://graphql-ruby.org/queries/tracing.html
- `GraphQL::Pro::Repository` is deprecated; see OperationStore for a replacement: https://graphql-ruby.org/operation_store/overview.html
### New Features
- New stable connection support based on GraphQL-Ruby 1.10's new pagination implementation. New classes provide better handling of `NULL` values in order-by columns and they can be applied on a field-by-field basis(`GraphQL::Pro::SqliteStableRelationConnection`, `GraphQL::Pro::MySQLStableRelationConnection`, `GraphQL::Pro::PostgresStableRelationConnection`).
### Bug Fix
- Add the Access query analyzer to class-based schemas
## 1.11.0 (10 Oct 2019)
### New Features
- Forwards-compatibility for graphql 1.10.0
- Support 1.10.0.pre1's input object argument `loads:` authorization
## 1.10.8 (8 Oct 2019)
### Bug Fix
- Continue authorizing input object arguments
- Use millisecond-aware string format for datetimes in cursors
## 1.10.7 (22 Jul 2019)
### Bug Fix
- Support multiple subscriptions in one document
## 1.10.6 (27 Jun 2019)
### New Features
- Support custom `#can_can_ability` methods on query context for CanCanIntegration
- Support custom `#pundit_user` method on query context for PunditIntegration
### Bug Fix
- Fix off-by-one error when paginating backwards from the last item in a stable relation connection
## 1.10.5 (11 May 2019)
### New Features
- Include expected HMAC digest in OperationStore debug output
## 1.10.4 (26 Mar 2019)
### Bug Fix
- Include content-length and content-type headers in OperationStore JSON responses
## 1.10.3 (13 Mar 2019)
### Bug Fix
- Support stable connections ordered by Arel SQL literals
## 1.10.2 (11 Mar 2019)
### Bug Fix
- Support stable connections on realized views (which don't have primary keys)
## 1.10.1 (8 Mar 2019)
### Bug Fix
- Pundit integration: support `pundit_policy_class` String names when scoping connections
## 1.10.0 (5 Mar 2019)
### New Features
- Add `GraphQL::Pro::Defer`, implementing `@defer` for streaming responses
## 1.9.13 (4 Mar 2019)
### Bug Fix
- Pundit integration: correctly authorize fields when Query root is nil
## 1.9.12 (22 Feb 2019)
### Bug Fix
- Pundit integration: use overriden `pundit_policy_class` for scoping and mutation authorization
## 1.9.11 (20 Feb 2019)
### Bug Fix
- Pundit integration: Fields use the owner's configured `pundit_policy_class` if there is one
- Pundit integration: avoid conflicts with `#initialize` for schema classes that don't need it
## 1.9.10 (19 Feb 2019)
### Bug Fix
- Support inheritance with `pundit_policy_class(...)`
## 1.9.9 (13 Feb 2019)
### New Features
- Support `pundit_policy_class(...)` and `pundit_policy_class:` to manually specify a class or class name.
## 1.9.8 (30 Jan 2019)
### New Features
- Inject `context` into policy lookup hooks instead of just the user
## 1.9.7 (30 Jan 2019)
### New Features
- Extract `pundit_policy` and `scope_by_pundit_policy` hooks for user override
## 1.9.6 (18 Jan 2019)
### Bug Fix
- Properly render subscription context in dashboard
## 1.9.5 (14 Jan 2019)
## Bug Fix
- Don't pass arrays to Pundit scopes (fixes https://github.com/rmosolgo/graphql-ruby/issues/2008)
## 1.9.4 (11 Jan 2019)
## Bug Fix
- Prepare for future compat with graphql-ruby 1.9
## 1.9.3 (3 Dec 2018)
### Bug Fix
- Include table name when adding a default order-by-id to ActiveRecord Relations
- Raise if a required cursor attribute is missing
- Improve `rake routes` output for operation store endpoint
- Support already-parsed queries in subscription RedisStorage
## 1.9.2 (2 Nov 2018)
### Bug Fix
- Derp, remove the dummy app's `.log` files from the gem bundle
- Fix ordering bug when a SQL function call doesn't have an explicit order
## 1.9.1 (1 Nov 2018)
### Bug Fix
- Fix Pusher reference in AblySubscriptions
## 1.9.0 (27 Oct 2018)
### New Features
- Add `GraphQL::Pro::AblySubscriptions` for GraphQL subscriptions over Ably.io transport
## 1.8.2 (22 Oct 2018)
### Bug Fix
- Support `NULLS LAST` in stable cursors
## 1.8.1 (16 Oct 2018)
### Bug Fix
- Improve operation store models to work when `config.active_record.primary_key_prefix_type` is set
## 1.8.0 (11 Oct 2018)
### New Features
- Support Rails 3.2 with OperationStore
- Use `.select` to filter items in CanCanIntegration
### Bug Fix
- Properly send an _ability_ and the configured `can_can_action` to `.accessible_by`
- Use a string (not integer) for `Content-Length` header in the dashboard
## 1.7.13 (2 Oct 2018)
### Breaking Change
- `PunditIntegration`: instead of raising `MutationAuthorizationFailed` when an argument fails authorization, it will send a `GraphQL::UnauthorizedError` to your `Schema.unauthorized_object` hook. (This is what all other authorization failures do.) To retain the previous behavior, in your base mutation, add:
```ruby
def unauthorized_by_pundit(owner, value)
# Raise a runtime error to halt query execution
raise "#{value} failed #{owner}'s auth check"
end
```
Otherwise, customize the handling of this behavior with `Schema.unauthorized_object`.
### Bug Fix
- Auth: mutation arguments which have authorization constraints but _don't_ load an object from the database will have _mutation instance_ passed to the auth check, not the input value.
## 1.7.12 (29 Aug 2018)
### New Features
- Add `GraphQL::Pro::CanCanIntegration` which leverages GraphQL-Ruby's built-in auth
## 1.7.11 (21 Aug 2018)
### Bug Fix
- `PunditIntegration`: Don't try to authorize loaded objects when they're `nil`
## 1.7.10 (10 Aug 2018)
### New Features
- Update `PunditIntegration` for arguments, unions, interfaces and mutations
## 1.7.9 (9 Aug 2018)
### New Features
- Add a new `PunditIntegration` which leverages the built-in authorization methods
## 1.7.8 (10 July 2018)
### Bug Fix
- Authorization: fix scoping lists of abstract type when there's no `#scope` method on the strategy
## 1.7.7 (10 May 2018)
### Bug Fix
- Fix ordering of authorization field instrumenter (put it at the end, not the beginning of the list)
## 1.7.6 (2 May 2018)
### New Features
- Authorization: Add `view`/`access`/`authorize` methods to `GraphQL::Schema::Mutation`
## 1.7.5 (19 Apr 2018)
### New Features
- Authorization: when a `fallback:` configuration is given, apply it to each field which doesn't have a configuration of its own or from its return type. _Don't_ apply that configuration at schema level (it's applied to each otherwise uncovered field instead).
## 1.7.4 (16 Apr 2018)
### New Features
- Support Mongoid::Criteria in authorization scoping
## 1.7.3 (12 Apr 2018)
### Bug Fix
- Fix authorization code for when `ActiveRecord` is not defined
## 1.7.2 (10 Apr 2018)
### Bug Fix
- Use a more permissive regexp (`/^\s*((?:[a-z._]+)\(.*\))\s*(asc|desc)?\s*$/im`) to parse SQL functions
## 1.7.1 (4 Apr 2018)
### Bug Fix
- Fix route helpers to support class-based schemas
## 1.7.0 (25 Mar 2018)
### New Features
- Support `1.8-pre` versions of GraphQL-Ruby
### Bug Fix
- Fix OperationStore when other query instrumenters need `.query_string`
## 1.6.5 (7 Feb 2018)
### Bug Fix
- Support `LEAST(...)` in stable cursors
## 1.6.4 (7 Feb 2018)
### Bug Fix
- Support `CASE ... END` in stable cursors
## 1.6.3 (26 Jan 2018)
### Bug Fix
- Support `FIELD(...)` in stable cursors
## 1.6.2 (13 Jan 2018)
### Bug Fix
- Improve detection of `OperationStore` for the dashboard
- Serve `Content-Type` and `Content-Length` headers with dashboard pages
- Better `Dashboard#inspect` for Rails routes output
- Use a string to apply order-by-primary-key for better Rails 3 support
## 1.6.1 (22 Nov 2017)
### New Features
- Support `composite_primary_keys` gem
## 1.6.0 (13 Nov 2017)
### Breaking Changes
- `GraphQL::Pro::UI` renamed to `GraphQL::Pro::Dashboard`
### Deprecations
- Routing method `.ui` was renamed to `.dashboard`
### New Features
- Added `GraphQL::Pro::Subscriptions`
- Added subscriptions component to Dashboard
## 1.5.9 (10 Oct 2017)
### Bug Fix
- Don't crash when scoping lists of abstract types with Pundit
## 1.5.8 (2 Oct 2017)
### New Features
- Use `authorize(:pundit, namespace: )` to lookup policies in a namespace instead of the global namespace.
### Bug Fix
- Introspection data is allowed through `fallback:` `authorize:` and `access:` filters. (It can be hidden with a `view:` filter.)
## 1.5.7 (20 Sept 2017)
### Bug Fix
- Properly return `nil` when a list of authorized objects returns `nil`
## 1.5.6 (19 Sept 2017)
### New Features
- Add `authorization(..., operation_store:)` option for authorizing operation store requests
## 1.5.5 (18 Sept 2017)
### New Features
- Support `ConnectionType.bidrectional_pagination?` in stable RelationConnection
## 1.5.4 (18 Sept 2017)
### Bug Fix
- Fix load issue when Rails is not present
## 1.5.3 (4 Sept 2017)
### Bug Fix
- Fix OperationStore views on PostgresQL
- Fix stable cursors when joined tables have the same column names
__Note:__ This is implemented by adding extra fields to the `SELECT`
clause with aliases like `cursor_#{idx}`, so you'll notice this in your
SQL logs.
## 1.5.2 (4 Aug 2017)
### Bug Fix
- Bump `graphql` dependency to `1.6`
## 1.5.1 (2 Aug 2017)
### New Features
- Routing extensions moved to `using GraphQL::Pro::Routes`
### Deprecations
- Deprecate `using GraphQL::Pro`, move extensions to `GraphQL::Pro::Routes`
## 1.5.0 (31 Jul 2017)
### New Features
- Add `GraphQL::Pro::OperationStore` for persisted queries with Rails
## 1.4.8 (14 Jul 2017)
### Bug Fix
- Update `authorization` to use type-level `resolve_type` hooks
## 1.4.7 (13 Jul 2017)
### Bug Fix
- Update authorization instrumentation for `graphql >= 1.6.5`
## 1.4.6 (6 Jul 2017)
### Bug Fix
- Fix typo in RelationConnection source
## 1.4.5 (6 Jul 2017)
### Bug Fix
- Correctly fall back to offset-based cursors with `before:` argument
## 1.4.4 (15 Jun 2017)
### New Features
- Add `Schema#unauthorized_object(obj, ctx)` hook for failed runtime checks
### Bug Fix
- Prevent usage of `parent_role:` with `view:` or `access:` (since parent role requires a runtime check)
- Fix versioned, encrypted cursors with 16-byte legacy cursors
## 1.4.3 (13 Jun 2017)
### New Features
- `OrderedRelationConnection` supports ordering by joined fields
### Bug Fix
- Update auth plugin for new Relay instrumenters
- `Pro::Encoder` supports `encoder(...)` as documented
## 1.4.2 (2 May 2017)
### Bug Fix
- Fix compatibility of `RelationConnection` and `RangeAdd` helper
## 1.4.1 (19 Apr 2017)
### New Features
- Add `:datadog` monitoring
## 1.4.0 (19 Apr 2017)
### New Features
- `ActiveRecord::Relation`s can be scoped by Pundit `Scope`s, CanCan `accessible_by`, or custom strategy's `#scope(gate, relation)` methods
- Default authorization configuration can be provided with `authorization(..., fallback: { ... })`
- Authorization's `:current_user` key can be customized with `authorization(..., current_user: ...)`
## 1.3.0 (7 Mar 2017)
### New Features
- Serve static, persisted queries with `GraphQL::Pro::Repository`
## 1.2.3 (2 May 2017)
### Bug Fix
- Fix compatibility of `RelationConnection` and `RangeAdd` helper
## 1.2.2 (6 Mar 2017)
### Bug Fix
- Raise `GraphQL::Pro::RelationConnection::InvalidRelationError` when a grouped, unordered relation is returned from a field. (This relation can't be stably paginated.)
## 1.2.1 (3 Mar 2017)
### New Features
- Formally support ActiveRecord `>= 4.1.0`
### Bug Fix
- Support grouped relations in `GraphQL::Pro::RelationConnection`
## 1.2.0 (1 Mar 2017)
### New Features
- Authorize fields based on their parent object, for example:
```ruby
AccountType = GraphQL::ObjectType.define do
name "Account"
# This field is visible to all users:
field :name, types.String
# This is only visible when the current user is an `:owner`
# of this account
field :account_balance, types.Int, authorize: { parent_role: :owner }
end
```
## 1.1.1 (22 Feb 2017)
### Bug Fixes
- Fix monitoring when `Query#selected_operation` is nil
## 1.1.0 (9 Feb 2017)
### New Features
- Add AppSignal monitoring platform
- Add type- and field-level opting in and opting out of monitoring
- Add `monitor_scalars: false` to skip monitoring on scalars
### Bug Fixes
- Fix `OrderedRelationConnection` when neither `first` nor `last` are provided (use `max_page_size` or don't limit)
## 1.0.4 (23 Jan 2017)
### Bug Fixes
- `OrderedRelationConnection` exposes more metadata methods: `parent`, `field`, `arguments`, `max_page_size`, `first`, `after`, `last`, `before`
## 1.0.3 (23 Jan 2017)
### Bug Fixes
- When an authorization check fails on a non-null field, propagate the null and add a response to the errors key (as if the field had returned null). It previously leaked the internal symbol `__graphql_pro_access_not_allowed__`.
- Apply a custom Pundit policy even when the value isn't `nil`. (It previously fell back to `Pundit.policy`, skipping a `pundit_policy_name` configuration.)
## 1.0.2
### Bug Fixes
- `OrderedRelationConnection` exposes the underlying relation as `#nodes` (like `RelationConnection` does), supporting custom connection fields.
## 1.0.1
### New Features
- CanCan integration now supports a custom `Ability` class with the `ability_class:` option:
```ruby
authorize :cancan, ability_class: CustomAbility
```
## 1.0.0
- `GraphQL::Pro` released
graphql-ruby-1.11.10/CHANGELOG-relay.md 0000664 0000000 0000000 00000006677 14141214530 0017226 0 ustar 00root root 0000000 0000000 # graphql-relay
### Breaking Changes
### Deprecations
### New Features
### Bug Fix
## 0.12.0 (21 Jul 2016)
### Breaking Changes
- Don't cache a global node identification config #51
To migrate, assign your node identification helper to the schema:
```ruby
NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define { ... }
MySchema.node_identification = NodeIdentification
```
### New Features
- Support lazy definition blocks from graphql-ruby 0.17
- Add `startCursor` and `endCursor` to `PageInfo` #60
### Bug Fix
- Support `field:` keyword for connection helper #58
## 0.11.2 (6 Jul 2016)
### New Features
- Include description for built-in objects #55
## 0.11.1 (24 Jun 2016)
### Bug Fix
- Correctly pass parent object to Connections #53
## 0.11.0 (19 Jun 2016)
### Breaking Changes
- `BaseType.define_connection` no longer caches the result to use as the default `BaseType.connection_type`. Now, store the result of `.define_connection` in a variable and pass that variable into the schema:
```ruby
# Capture the returned type:
SomethingCustomConnectionType = SomethingType.define_connection { ... }
DifferentThingType = GraphQL::ObjectType.define do
# And pass it to the connection helper:
connection :somethings, SomethingCustomConnectionType
end
```
### New Features
- Support for custom edge types / classes #50
- Support for multiple connection classes #50
## 0.10.0 (31 May 2016)
### New Feature
- Support `graphql` 0.14.0 #47
### Bug Fix
- Use strings as argument names, not symbols #47
## 0.9.5
### New Feature
- Root `id` field may have a description #43
## 0.9.4 (29 Apr 2016)
### Bug Fix
- Fix Node interface to support GraphQL 0.13.0+
## 0.9.2 (29 Apr 2016)
### Bug Fix
- Fix Node interface when type_from_object returns nil
## 0.9.1 (6 Apr 2016)
### Bug Fix
- Respond to connection fields without any pagination arguments
- Limit by `max_page_size` even when no arguments are present
## 0.9.0 (30 Mar 2016)
### Breaking change
- Remove the `order` argument from connection fields. This isn't part of the spec and shouldn't have been there in the first place!
You can implement this behavior with a custom argument, for example:
```ruby
field :cities, CityType.connection_type do
argument :order, types.String, default_value: "name"
resolve ->(obj, args, ctx) {
obj.order(args[:order])
}
end
```
### Bug Fix
- Include the MIT license in the project's source
## 0.8.1 (22 Mar 2016)
### Bug Fix
- Accept description for Mutations
## 0.8.0 (20 Mar 2016)
### New Feature
- Accept configs for `to_global_id` and `from_global_id`
- Support `graphql` 0.12+
## 0.7.1 (29 Feb 2016)
### Bug Fix
- Limit the `count(*)` when testing next page with ActiveRecord #28
## 0.7.0 (20 Feb 2016)
### New Feature
- `max_page_size` option for connections
- Support ActiveSupport 5.0.0.beta2
## 0.6.2 (11 Feb 2016)
### Bug Fix
- Correctly cast values from connection cursors #21
- Use class _name_ instead of class _object_ when finding a connection implementation (to support Rails autoloading) #16
## 0.6.1 (14 Dec 2015)
### Bug Fix
- Stringify `id` when passed into `to_global_id`
## 0.6.0 (11 Dec 2015)
### Breaking Change
- `GlobalNodeIdentification#object_from_id(id, ctx)` now accepts context as the second argument #9
## 0.5.1 (11 Dec 2015)
### Feature
- Allow custom UUID join string #15
### Bug Fix
- Remove implicit ActiveSupport dependency #14
graphql-ruby-1.11.10/CHANGELOG.md 0000664 0000000 0000000 00000325032 14141214530 0016101 0 ustar 00root root 0000000 0000000 # Changelog
### Breaking changes
### Deprecations
### New features
### Bug fixes
# 1.11.10 (5 Nov 2021)
### Bug fixes
- Properly hook up `Schema.max_validation_errors` at query runtime #3690
# 1.11.9
### New Features
- `Schema.max_validation_errors(val)` limits the number of errors that can be added during static validation #3675
# 1.11.8 (12 Feb 2021)
### Bug fixes
- Improve performance of `Schema.possible_types(t)` for object types #3172
# 1.11.7 (18 January 2021)
### Breaking changes
- Incoming integer values are properly bound (as per the spec) #3206 To continue receiving out-of-bound integer values, add this to your schema's `def self.type_error(err, ctx)` hook:
```ruby
def self.type_error(err, ctx)
if err.is_a?(GraphQL::IntegerDecodingError)
return err.value # return it anyways, since this is how graphql-ruby used to work
end
# ...
end
```
### New features
- Support Ruby 3.0 #3278
- Add validation timeout option #3234
- Support Prometheus custom_labels in GraphQLCollector #3215
### Bug fixes
- Handle `GraphQL::UnauthorizedError` in interpreter in from arguments #3276
- Set description for auto-generated `input:` argument #3141
- Improve performance of fields will merge validation #3228
- Use `Float` graphql type for ActiveRecord decimal columns #3246
- Add some custom methods to ArrayConnection #3238
- Fix generated fields for types ending Connection #3223
- Improve runtime performance #3217
- Improve argument handling when extensions shortcut the defined resolve #3212
- Bind scalar ints as per the spec #3206
- Validate that input object names are unique #3205
## 1.11.6 (29 October 2020)
### Breaking changes
FieldExtension: pass extended values instead of originals to `after_resolve` #3168
### Deprecations
### New features
- Accept additional options in `global_id_field` macro #3196
### Bug fixes
- Use `graphql_name` in `UnauthorizedError` default message (fixes #3174) #3176
- Improve error handling for base 64 decoding (in `UniqueWithinType`) #3179
- Fix `.valid_isolated_input?` on parsed schemas (fixes #3181) #3182
- Fix fields nullability in subscriptions documentation #3194
- Update `RangeAdd` to use new connections when available #3195
## 1.11.5 (30 September 2020)
### New features
- SanitizedPrinter: accept `inline_variables: false` option and add `#redact_argument_value?` and `#redacted_argument_value` hooks #3167
- GraphQL::Schema::Timeoout#max_seconds(query) can provide a per-query timeout duration #3167
- Implement Interpreter::Arguments#fetch
- Assign `current_{path,field,arguments,object}` in `query.context` #3139. The values at these keys change while the query is running.
- ActionCableSubscriptions: accept `use(..., namespace: "...")` for running multiple schemas in the same application #3076
- Add `deprecation_reason:` to arguments #3015
### Bug fixes
- SanitizedPrinter: Fix lists and JSON scalars #3171
- Improve retained memory in Schema.from_definition #3153
- Make it easier to cache schema parsing #3153
- Make sure deprecated arguments aren't required #3137
- Use `.empty?` instead of `.length.zero?` in lexer #3134
- Return a proper error when a stack error happens #3129
- Assert valid input types on arguments #3120
- Improve Validator#validate performance #3125
- Don't wrap `RawValue` in ConnectionExtension #3122
- Fix interface possible types visibility #3124
## 1.11.4 (24 August 2020)
### Breaking changes
### New features
- Add `node_nullable` option for `edge_type` #3083
- Use module namespacing for template generators #3098
### Bug fixes
- Rescue `SystemStackError`s during validation #3107
- Add `require 'digest/sha2'` for fingerprint #3103
- Optimize `GraphQL::Query::Context#dig` #3090
- Check if new connections before calling method on it (fixes #3059) #3100
- Thread field owner type through interpreter runtime (fixes #3086) #3099
- Check for visible interfaces on the type in warden #3096
- Update `AppOpticsTracing` with latest changes in `PlatformTracing` #3097
- Use throw instead of raise to halt subscriptions early #3084
- Optimize `GraphQL::Query::Context#fetch` #3081
## 1.11.3 (13 August 2020)
### Breaking changes
- Reverted the `required` and `default_value` argument behaviour change in 1.11.2 since it was not spec compliant #3066
### New features
- Improve resolver method conflict warning #3069, #3062
- Store arguments on `Mutation` instances after they're loaded #3073
### Bug fixes
- Fix connection wrappers on lazy lists #3070
## 1.11.2 (1 August 2020)
### Breaking changes
- Previously, GraphQL-Ruby allowed _both_ `default_value: ...` and `required: true` in argument definitions. However, this definition doesn't make sense -- a default value is never used for a `required: true` argument. This configuration now raises an error. Remove the `default_value:` to get rid of the error. #3011
### New features
- Support Date, Time and OpenStruct in Subscription::Serialize #3057
### Bug fixes
- Speed up `DELETE_NODE` check #3053
- Reject invalid enum values during definition #3055
- Fix `.trigger` from unsubscribed ActionCable channel #3051
- Fix error message from VariablesAreUsedAndDefined for anonymous queries #3050
- Fix renaming variable identifiers in AST visitor #3045
- Reject `default_value: ...` used with `required: true` during definition #3011
- Use the configured `edge_class:` with new connections #3036
- Don't call visible for unused arguments #3030, #3031
- Properly load directives from introspection results #3021
- Reject interfaces as members of unions #3024
- Load deprecation reason from introspection results #3014
- Fix arguments caching when extension modify arguments #3009
## 1.11.1 (17 June 2020)
### New Features
- Add `StatsdTracing` #2996
### Bug Fixes
- Raise the proper `InvalidNullError` when a mutation field returns an invalid `nil` #2997
## 1.11.0 (13 June 2020)
### Breaking changes
- Global tracers are removed (deprecated since 1.7.4) #2936
- Fields defined in camel case (`field :doStuff`) will not line up to methods that are underscore case (`def do_stuff`). Instead, the given symbol is used _verbatim_. #2938 To work around this:
- Change the name of the method to match the field (eg, `def doStuff`)
- Change the name of the field to match the method (eg, `field :do_stuff`, let graphql-ruby camelize it for you)
- Or, add `resolver_method: :do_stuff` to explicitly map the field to a method on the object type definition
You can probably find instances of this in your application with a regexp like `/field :[a-z]+[A-Z]/`, and review them.
### New features
- `extend SubscriptionRoot` is no longer necessary #2770
- Add `broadcast: true` option to subscriptions #2959
- Add `Edge#parent` to new connection classes #2961
### Bug fixes
- Use the field name as configured for hash key or method name #2906
## 1.10.12 (13 June 2020)
### Bug fixes
- Fix compatibility of `YYYY-mm-dd` with `Types::ISO8601DateTime` #2989
- Remove unused ivar in InputObject #2987
## 1.9.21 (12 June 2020)
### Bug fixes
- Fix `extras:` on subscription fields #2983
## 1.10.11 (11 June 2020)
### New features
- Scout tracer adds transaction name to traces #2969
- `resolve_type` can optionally return a resolved object #2976
- DateTime scalar returns a `Time` for better timezone handling #2973
- Interpreter memory improvements #2980, #2978
- Support lazy values from field-level authorization hooks #2977
- Object generator infers fields from model classes #2954
- Add type-specific runtime errors #2957
### Bug fixes
- Fix for error when using `extras:` with subscription fields #2984
- Improve Schema.error_handler inheritance #2975
- Add raw_value to conflict warning list #2958
- Arguments#each_value yields ArgumentValues #2956
## 1.10.10 (20 May 2020)
### Bug Fixes
- Fix lazy `loads:` with list arguments #2949
- Show object fields even when inherited ones are hidden #2950
- Use `reverse_each` in instrumenters #2945
- Fix underscored names in introspection loader #2941
- Fix array input to Date/DateTime types #2927
- Fix method conflict warnings on schema loader #2934
- Fix some Ruby 2.7 warnings #2925
## 1.9.20 (20 May 2020)
### Bug fixes
- Fix `default_value: {}` on Ruby 2.7
## 1.10.9 (4 May 2020)
### New features
- Add `Interpreter::Arguments#dig` #2912
## 1.10.8 (27 April 2020)
### Breaking changes
- With the interpreter, `Query#arguments_for` returns `Interpreter::Arguments` instances instead of plain hashes. (They should work mostly the same, though.) #2881
### New features
- `Schema::Field#introspection?` returns true for built-in introspection-related fields
### Bug fixes
- Fix Ruby 2.7 warning on `Schema.to_json` #2905
- Pass `&block` to nested method calls to reduce stack depths #2900
- Fix lazy `loads:` with list arguments #2894
- Fix `loads:` on nested input object #2895
- Rescue base64 encoding errors in the encoder #2896
## 1.10.7 (16 April 2020)
### Breaking changes
- `Schema.from_introspection(...)` builds class-based schemas #2876
### New features
- `Date` and `DateTime` types also accept well-formatted strings #2848
- `Schema.from_introspection(...)` builds class-based schemas #2876
- `Schema#to_definition` now dumps all directives that were part of the original IDL, if the schema was parsed with `.from_definition` #2879
### Bug fixes
- Fix memory leak in legacy runtime #2884
- Fix interface inheritance in legacy runtime #2882
- Fix description on `List` and `NonNull` types (for introspection) #2875
- Fix over-rescue of NoMethodError when building list responses #2887
## 1.10.6 (6 April 2020)
### New features
- Add options to `implements(...)` and inteface type visibility #2791
- Add `Query#fingerprint` for logging #2859
- Add `--playground` option to install generator #2839
- Support lazy-loaded objects from input object `loads:` #2834
### Bug fixes
- Fix `Language::Nodes` equality: move `eql?` to `==` #2861
- Make rake task properly detect rails `environment` task #2862
- Fix `nil` override for `max_page_size` #2843
- Fix `pageInfo` methods when they're called before `nodes` #2845
- Make the default development error match a normal GraphQL error #2825
- Fix `loads:` with `require: false` #2833
- Fix typeerror for `BigInt` given `nil` #2827
## 1.10.5 (12 March 2020)
### New features
- Add `#field_complexity` hook to `AST::QueryComplexity` analyzer #2807
### Bug fixes
- Pass `nonce: true` when encoding cursors #2821
- Ignore empty-string cursors #2821
- Properly pass along `Analysis::AST` to schema instances #2820
- Support filtering unreachable types in schemas from IDL #2816
- Use `Query#arguments_for` for lookahead arguments #2811
- Fix pagination bug on old connections #2799
- Support new connection system on old runtime #2798
- Add details to raise CoercionErrors #2796
## 1.10.4 (3 March 2020)
### Breaking changes
- When an argument is defined with a symbol (`argument :my_arg, ...`), that symbol is used _verbatim_ to build Ruby keyword arguments. Previously it was converted to underscore-case, but this autotransform was confusing and wrong in some cases. You may have to change the symbol in your `argument(...)` configuration if you were depending on that underscorization. #2792
- Schemas from `.from_definition` previously had half-way connection support. It's now completely removed, so you have to add connection wrappers manually. See #2782 for migration notes.
### New features
- Add `Appoptics` tracing #2789
- Add `Query#sanitized_query_string` #2785
- Improved duplicate type error message #2777
### Bug fixes
- Fix arguments ending in numbers, so they're injected with the same name that they're configured with #2792
- Improve `Query#arguments_for` with interpreter #2781
- Fix visitor replacement of variable definitions #2752
- Remove half-broken connection handling from `Schema.from_definition` #2782
## 1.10.3 (17 Feb 2020)
### New features
- Support `loads:` with plain field arguments #2720
- Support `raw_value(...)` to halt execution with a certain value #2699
- `.read_subscription` can return `nil` to bypass executing a subscription #2741
### Bug fixes
- Connection wrappers are properly inherited #2750
- `prepare(...)` is properly applied to default values in subscription fields #2748
- Code tidying for RSpec warnings #2741
- Include new analysis module when generating a schema #2734
- Include directive argument types in printed schemas #2733
- Use `module_parent_name` in Rails #2713
- Fix overriding default scalars in build_from_definition #2722
- Fix some non-null errors in lists #2651
## 1.10.2 (31 Jan 2020)
### Bug fixes
- Properly wrap nested input objects in instances #2710
## 1.10.1 (28 Jan 2020)
### Bug fixes
- Include Interface-level `orphan_types` when building a schema #2705
- Properly re-enter selections in complexity analyzer #2595
- Fix input objects with null values #2690
- Fix default values of `{}` in `.define`-based schemas #2703
- Fix field extension presence check #2689
- Make new relation connections more efficient #2697
- Don't include fields `@skip(if: true)` or `@include(if: false)` in lookahead #2700
## 1.9.19 (28 Jan 2020)
### Bug Fixes
- Fix argument default value of `{}` with Ruby 2.7 argument handling #2704
## 1.10.0 (20 Jan 2020)
### Breaking Changes
- Class-based schemas using the new interpreter will now use _definition classes_ at runtime. #2363 (Previously, `.to_graphql` methods were used to generate singletons which were used at runtime.) This means:
- Methods that used to receive types at runtime will now receive classes instead of those singletons.
- `.name` will now call `Class#name`, which will give the class name. Use `.graphql_name` to get the name of a GraphQL type. (Fields, arguments and directives have `.graphql_name` too, so you can use it everywhere.)
- Some methods that return hashes are slow because they merge hashes according to class inheritance, for example `MySchema.types` and `MyObjectType.fields`. Instead:
- If you only need one item out of the Hash, use `.get_type(type_name)` or `.get_field(field_name)` instead. Those methods find a match without performing Hash merges.
- If you need the whole Hash, get a cached value from `context.warden` (an instance of `GraphQL::Schema::Warden`) at runtime. Those values reflect the types and fields which are permitted for the current query, and they're cached for life of the query. Check the API docs to see methods on the `warden`.
- Class-based schemas using the interpreter _must_ add `use GraphQL::Analysis::AST` to their schema (and update their custom analyzers, see https://graphql-ruby.org/queries/ast_analysis.html) #2363
- ActiveSupport::Notifications events are correctly named in event.library format #2562
- Field and Argument `#authorized?` methods now accept _three_ arguments (instead of 2). They now accept `(obj, args, ctx)`, where `args` is the arguments (for a field) or the argument value (for an argument). #2520
- Double-null `!!` is disallowed by the parser #2397
- (Non-interpreter only) The return value of subscription fields is passed along to execute the subscription. Return `nil` to get the previous behavior. #2536
- `Schema.from_definition` builds a _class-based schema_ from the definition string #2178
- Only integers are accepted for `Int` type #2404
- Custom scalars now call `.coerce_input` on all input values - previously this call was skipped for `null` values.
### Deprecations
- `.define` is deprecated; class-based schema definitions should be used instead. If you're having trouble or you can't find information about an upgrade path, please open an issue on GitHub!
### New Features
- Add tracing events for `.authorized?` and `.resolve_type` calls #2660
- `Schema.from_definition` accepts `using:` for installing plugins (equivalent to `use ...` in class-based schemas) #2307
- Add `$` to variable names in error messages #2531
- Add invalid value to argument error message #2531
- Input object arguments with `loads:` get the loaded object in their `authorized?` hook, as `arg` in `authorized?(obj, args, ctx)`. #2536
- `GraphQL::Pagination` auto-pagination system #2143
- `Schema.from_definition` builds a _class-based schema_ from the definition string #2178
### Bug Fixes
- Fix warnings on Ruby 2.7 #2668
- Fix Ruby keyword list to support Ruby 2.7 #2640
- Reduce memory of class-based schema #2636
- Improve runtime performance of interpreter #2630
- Big numbers (ie, greater than Ruby's `Infinity`) no longer :boom: when being reserialized #2320
- Fix `hasNextPage`/`hasPrevious` page when max_page_size limits the items returned #2608
- Return parse errors for empty documents and empty argument lists #2344
- Properly serialize `defaultValue` of input objects containing enum values #2439
- Don't crash when a query contains `!!`. #2397
- Resolver `loads:` assign the value to argument `@loads` #2364
- Only integers are accepted for `Int` type #2404
## 1.9.18 (15 Jan 2020)
### New features
- Support disabling `__type` or `__schema` individually #2657
- Support Ruby 2.7, and turn on CI for it :tada: #2665
### Bug fixes
- Fix Ruby 2.7 warnings #2653 #2669
- Properly build camelized names for directive classes #2666
- Use schema-defined context class for SDL generation #2656
- Apply visibility checks when generating SDL #2637
## 1.9.17 (17 Dec 2019)
### New features
- Scoped context for propagating values to child fields #2634
- Add `type_membership_class` with possible_type visibility #2391
### Bug fixes
- Don't return unreachable types in introspection response #2596
- Wrap more of execution with error handling #2632
- Fix InputObject `.prepare` for the interpreter #2624
- Fix Ruby keyword list to support Ruby 2.7 #2640
- Fix performance of urlsafe_encode64 backport #2643
## 1.9.16 (2 Dec 2019)
### Breaking changes
- `GraphQL::Schema::Resolver#initialize` accepts a new keyword argument, `field:`. If you have overriden this method, you'll have to add that keyword to your argument list (and pass it along to `super`.) #2605
### Deprecations
- `SkylightTracing` is disabled; the Skylight agent contains its own GraphQL support. See Skylight's docs for migration. #2601
### New features
### Bug fixes
- Fix multiplex max_depth calculation #2613
- Use monotonic time in TimeoutMiddleware #2622
- Use underscored names in Mutation generator #2617
- Fix lookahead when added to mutations in their `field(...)` definitions #2605
- Handle returned lists of errors from Mutations #2567
- Fix lexer error on block strings containing only newlines #2598
- Fix mutation generator to reference the new base class #2580
- Use the right camelization configuration when generating subscription topics #2552
## 1.9.15 (30 Oct 2019)
### New features
- Improve parser performance #2572
- Add `def prepare` API for input objects #1869
- Support `extensions` config in Resolver classes #2570
- Support custom `.connection_extension` in field classes #2561
- Warn when a field name is a Ruby keyword #2559
- Improve performance for ActiveRecord connection #2547
### Bug fixes
- Fix errantly generated `def resolve_field` method in `BaseField` #2578
- Comment out the `null_session` handling in the generated controller, for better compat with Rails API mode #2557
- Fix validation error with duplicate, self-referencing fragment #2577
- Revert the `.authorized?` behavior of InputObjects to handle cyclical references. See 1.10.0.pre1 for a better behavior. #2576
- Replace `NotImplementedError` (which is meant for operating system APIs) with `GraphQL::RequiredImplementationMissingError` #2543
## 1.9.14 (14 Oct 2019)
### New features
- Add `null_session` CSRF handing in `install` generator #2524
- Correctly report InputObjects without arguments and Objects without fields as invalid #2539 #2462
### Bug fixes
- Fix argument incompatibility #2541
- Add a `require` for `Types::ISO8691Date` #2528
- Fix errors re-raised after lazy fields #2525
## 1.9.13 (8 Oct 2019)
### Breaking changes
- Enum values were (erroneously) accepted as ID or String values, but they aren't anymore. #2505
### New features
- Add `Query#executed?` #2486
- Add `Types::ISO8601Date` #2471
### Bug fixes
- Don't accept Enums as IDs or Strings #2505
- Call `.authorized?` hooks on arguments that belong to input objects #2519
- Fix backslash parsing edge case #2510
- Improve performance #2504 #2498
- Properly stringify keys in error extensions #2508
- Fix `extras:` handling in RelayClassicMutation #2484
- Use `Types::BaseField` in scaffold #2470
## 1.9.12 (9 Sept 2019)
### Breaking Changes
- AST Analyzers follow fragments spreads as if they were inline fragments. #2463
### New Features
- `use GraphQL::Execution::Errors` provides error handling for the new interpreter. #2458
### Bug Fixes
- Fix false positive on enum value validation #2454
## 1.9.11 (29 Aug 2019)
### Breaking Changes
- Introspection fields are now considered for query depth validations, so you'll need at least `max_depth: 13` to run the introspection query #2437
### New features
- Add `extras` setter to `GraphQL::Schema::Field` #2450
- Add extensions in `CoercionError` #2431
### Bug fixes
- Make `extensions` kwarg on field on more flexible for extensions with options #2443
- Fix list validation error handling #2441
- Include introspective fields in query depth calculations #2437
- Correct the example for using 'a class method to generate fields' #2435
- Enable multiple execution errors for Fields defined to return a list #2433
## 1.9.10 (20 Aug 2019)
### New features
- Support required arguments with default values #2416
### Bug fixes
- Properly disable `max_complexity` and `max_depth` when `nil` is passed #2409
- Fix printing class-based schemas #2406
- Improve field method naming conflict check #2420
## 1.9.9 (30 July 2019)
### New features
- Memoize generated strings in `.to_query_string` #2400
- Memoize generated strings in platform tracing #2401
### Bug fixes
- Support class-based subscription type in `.define`-based schema #2403
## 1.9.8 (24 July 2019)
### New features
- Schema classes pass their configuration to subclasses #2384
- Improve memory consumption of lexer and complexity validator #2389
- The `install` generator creates a BaseArgument #2379
- When a field name conflicts with a built-in method name, give a warning #2376
### Bug fixes
- When a resolver argument uses `loads:`, the argument definition will preserve the type in `.loads` #2365
- When an required argument is hidden, it won't add a validation error #2393
- Fix handling of invalid UTF-8 #2372, #2377
- Empty block strings are parsed correctly #2381
- For resolvers, only authorize arguments once #2378
## 1.9.7 (25 June 2019)
### Breaking changes
- `Analysis::AST::Visitor#argument_definition` no longer returns the _previous_ argument definition. Instead, it returns the _current_ argument definition and `#previous_argument_definition` returns the previous one. You might have to replace calls to `.argument_definition` with `.previous_argument_definition` for compatibility. #2226
### New features
- Accept a `subscription_scope` configuration in Subscription classes #2297
- Add a `disable_introspection_entry_points` configuration in Schema classes #2327
- Add `Analysis::AST::Visitor#argument_definition` which returns the _current_ argument definition, `#previous_argument_definition` returns the _previous_ one #2226
- Run CI on Ruby 2.6 #2328
- Autogenerate base field class #2216
- Add timeout support with interpreter #2220
### Bug fixes
- Fix Stack overflow when calling `.to_json` on input objects #2343
- Fix off-by-one error with hasNextPage and ArrayConnections #2349
- Fix GraphQL-Pro operation store compatibility #2350
- Fix class-based transformer when multiple mutations are in one file #2309
- Use `default_graphql_name` for Edge classes #2224
- Support nested `loads:` with input objects #2323
- Support `max_complexity` with multiplex & AST analysis #2306
## 1.9.6 (23 May 2019)
### Bug fixes
- Backport `String#-@` for Ruby 2.2 support #2305
## 1.9.5 (22 May 2019)
### New features
- Support `rescue_from` returning `GraphQL::ExecutionError` #2140
- Accept `context:` in `Schema.validate` #2256
- Include `query:` in interpreter tracing for `execute_field` and `execute_field_lazy` #2236
- Add `Types::JSON` #2227
- Add `null:` option to `BaseEdge.node_type` #2249
### Bug fixes
- Fix Ruby 2.2 compatibility #2302
- Distinguish aliased selections in lookahead #2266
- Properly show list enum default values in introspection #2263
- Performance improvements: #2289, #2244, #2258, #2257, #2240
- Don't recursively unwrap inputs for RelayClassicMutation #2236
- Fix `Schema::Field#scoped?` when no return type #2255
- Properly forward more authorization errors #2165
- Raise `ParseError` for `.parse(nil)` #2238
## 1.9.4 (5 Apr 2019)
### Breaking Changes
- `GraphQL::Schema::Resolver::LoadApplicationObjectFailedError` was renamed to `GraphQL::LoadApplicationObjectFailedError`. (This will only break if you're referencing the class by name and running Ruby 2.5+) #2080
### New features
- Add `Types::BigInt` #2150
- Add auto-loading arguments support in Input Object types #2080
- Add analytics tag to Datadog tracing #2154
### Bug fixes
- Fix `Query#execute` when no explicit query string is passed in #2142
- Fix when a root type returns nil because unauthorized #2144
- Fix tracing `node` by threading `owner:` through field tracing #2156
- Fix interpreter handling of exceptions raised during argument preparation #2198
- Fix ActionCableLink when there are errors but no data #2176
- Provide empty hash as default option for field resolvers #2189
- Prevent argument names from overwriting Arguments methods #2171
- Include array indices in error paths #2162
- Handle non-node arrays in AST visitor #2161
## 1.9.3 (20 Feb 2019)
### Bug fixes
- Fix `Schema::Subscription` when it has no arguments #2135
- Don't try to scope `nil`, just skip scoping altogether #2134
- Fix when a root `.authorized?` returns `false` and there's no `root_value` #2136
- Fix platform tracing with interpreter & introspection #2137
- Support root Subscription types with name other than `Subscription` #2102
- Fix nested list-type input object nullability validation #2123
## 1.9.2 (15 Feb 2019)
### Bug fixes
- Properly support connection fields with resolve procs #2115
## 1.9.1 (14 Feb 2019)
### Bug fixes
- Properly pass errors to Resolver `load_application_object_failed` methods #2110
## 1.9.0 (13 Feb 2019)
### Breaking Changes
- AST nodes are immutable. To modify a parsed GraphQL query, see `GraphQL::Language::Visitor` for its mutation API, which builds a new AST with the specified mutations applied. #1338, #1740
- Cursors use urlsafe Base64. This won't break your clients (it's backwards-compatible), but it might break your tests, so it's listed here. #1698
- Add `field(..., resolver_method:)` for when GraphQL-Ruby should call a method _other than_ the one whose name matches the field name (#1961). This means that if you're using `method:` to call a different method _on the Schema::Object subclass_, you should update that configuration to `resolver_method:`. (`method:` is still used to call a different method on the _underlying application object_.)
- `Int` type now applies boundaries as [described in the spec](https://facebook.github.io/graphql/June2018/#sec-Int) #2101. To preserve the previous, unbounded behavior, handle the error in your schema's `.type_error(err, ctx)` hook, for example:
```ruby
class MySchema < GraphQL::Schema
def self.type_error(err, ctx)
if err.is_a?(GraphQL::IntegerEncodingError)
# Preserve the previous unbounded behavior
# by returning the out-of-bounds value
err.integer_value
else
super
end
end
end
```
- `field(...)` configurations don't create implicit method definitions (#1961). If one resolver method depended on the implicitly-created method from another field, you'll have to refactor that call or manually add a `def ...` for that field.
- Calling `super` in a field method doesn't work anymore (#1961)
- Error `"problems"` are now in `"extensions" : { "problems": ... }` #2077
- Change schema default to `error_bubbling false` #2069
### New Features
- Add class-based subscriptions with `GraphQL::Schema::Subscription` #1930
- Add `GraphQL::Execution::Interpreter` (#1394) and `GraphQL::Analysis::AST` (#1824) which together cut GraphQL overhead by half (time and memory)
- Add `Schema.unauthorized_field(err)` for when `Field#authorized?` checks fail (#1994)
- Add class-based custom directives for the interpreter (#2055)
- Add `Schema::FieldExtension` for customizing field execution with class-based fields #1795
- Add `Query#lookahead` for root-level selection info #1931
- Validation errors have `"extensions": { ... }` which includes metadata about that error #1970
### Bug fixes
- Fix list-type arguments passed with a single value #2085
- Support `false` as an Enum value #2050
- Support `hash_key:` fields when the key isn't a valid Ruby method name #2016
## 1.8.15 (13 Feb 2019)
### Bug fixes
- Fix unwrapping inputobject types when turning arguments to hashes #2094
- Support lazy objects from `.resolve_type` hooks #2108
## 1.8.14 (9 Feb 2019)
### Bug Fixes
- Fix single-item list inputs that aren't passed as lists #2095
## 1.8.13 (4 Jan 2019)
### Bug fixes
- Fix regression in block string parsing #2032
## 1.8.12 (3 Jan 2019)
### Breaking changes
- When an input object's argument has a validation error, that error is reported on the _argument_ instead of its parent input object. #2013
### New features
- Add `error_bubbling false` Schema configuration for nicer validation of compound inputs #2013
- Print descriptions as block strings in SDL #2011
- Improve string-to-constant resolution #1810
- Add `Query::Context#to_hash` for splatting #1955
- Add `#dig` to `Schema::InputObject` and `Query::Arguments` #1968
- Add `.*_execution_strategy` methods to class-based schemas #1914
- Accept multiple errors when adding `.rescue_from` handlers #1991
### Bug fixes
- Fix scalar tracing in NewRelic and Skylight #1954
- Fix lexer for multiple block strings #1937
- Add `unscope(:order)` when counting relations #1911
- Improve build-from-definition error message #1998
- Fix regression in legacy compat #2000
## 1.8.11 (16 Oct 2018)
### New features
- `extras: [:lookahead]` injects a `GraphQL::Execution::Lookahead`
### Bug fixes
- Fix type printing in Printer #1902
- Rescue `GraphQL::ExecutionError` in `.before_query` hooks #1898
- Properly load default values that are lists of input objects from the IDL #1874
## 1.8.10 (21 Sep 2018)
### Bug fixes
- When using `loads:` with a nullable mutation input field, allow `null` values to be provided. #1851
- When an invalid Base64 encoded cursor is provided, raise a `GraphQL::ExecutionError` instead of `ArgumentError`. #1855
- Fix an issue with `extras: [:path]` would use the field's `path` instead of the `context`. #1859
### New features
- Add scalar type generator `rails g graphql:scalar` #1847
- Add `#dig` method to `Query::Context` #1861
## 1.8.9 (13 Sep 2018)
### Breaking changes
- When `field ... ` is called with a block and the block has one argument, the field is yielded, but `self` inside the block is _not_ changed to the field. #1843
### New features
- `extras: [...]` can inject values from the field instance #1808
- Add `ISO8601DateTime.time_precision` for customization #1845
- Fix input objects with default values of enum #1827
- `Schema.sync_lazy(value)` hook for intercepting lazy-resolved objects #1784
### Bug fixes
- When a field block is provided with an arity of `1`, yield the field #1843
## 1.8.8 (27 Aug 2018)
### Bug fixes
- When using `RelayClassicMutation`, `client_mutation_id` will no longer be passed to `authorized?` method #1771
- Fix issue in schema upgrader script which would cause `.to_non_null_type` calls in type definition to be ignored #1783
- Ensure enum values respond to `graphql_name` #1792
- Fix infinite resolution bug that could occur when an exception not inheriting from `StandardError` is thrown #1804
### New features
- Add `#path` method to schema members #1766
- Add `as:` argument to allow overriding the name of the argument when using `loads:` #1773
- Add support for list of IDs when using `loads:` in an argument definition #1797
## 1.8.7 (9 Aug 2018)
### Breaking changes
- Some mutation authorization hooks added in 1.8.5 were changed, see #1736 and #1737. Roughly:
- `before_prepare` was changed to `#ready?`
- `validate_*` hooks were replaced with a single `#authorized?` method
### Bug fixes
- Argument default values include nested default values #1728
- Clean up duplciate method defs #1739
### New features
- Built-in support for Mongoid 5, 6, 7 #1754
- Mutation `#ready?` and `#authorized?` may halt flow and/or return data #1736, #1737
- Add `.scope_items(items, ctx)` hook for filtering lists
- Add `#default_graphql_name` for overriding default logic #1729
- Add `#add_argument` for building schemas #1732
- Cursors are decoded using `urlsafe_decode64` to future-proof for urlsafe cursors #1748
## 1.8.6 (31 July 2018)
### Breaking changes
- Only allow Objects to implement actual Interfaces #1715. Use `include` instead for plain Ruby modules.
- Revert extending interface methods onto Objects #1716. If you were taking advantage of this feature, you can create a plain Ruby module with the functionality and include it in both the interface and object.
### Deprecations
### New features
- Support string descriptions (from June 2018 GraphQL spec) #1725
- Add some accessors to Schema members #1722
- Yield argument for definition block with arity of one #1714
- Yield field for definition blocks with arity of one #1712
- Support grouping by "endpoint" with skylight instrumentation #1663
- Validation: Don't traverse irep if no handlers are registered #1696
- Add `nodes_field` option to `edge_type` to hide nodes field #1693
- Add `GraphQL::Types::ISO8601DateTime` to documentation #1694
- Conditional Analyzers #1690
- Improve error messages in `ActionCableSubscriptions` #1675
- Add Prometheus tracing #1672
- Add `map` to `InputObject` #1669
### Bug fixes
- Improve the mutation generator #1718
- Fix method inheritance for interfaces #1709
- Fix Interface inheritance chain #1686
- Fix require in `tracing.rb` #1685
- Remove delegate for `FieldResolutionContext#schema` #1682
- Remove duplicated `object_class` method #1667
## 1.8.5 (10 July 2018)
### Breaking changes
- GraphQL validation errors now include `"filename"` if the parsed document had a `filename` #1618
### Deprecations
- `TypeKind#resolves?` is deprecated in favor of `TypeKind#abstract?` #1619
### New features
- Add Mutation loading/authorization system #1609
- Interface `definition_methods` are inherited by object type classes #1635
- include `"filename"` in GraphQL errors if the parsed document has a filename #1618
- Add `Schema::InputObject#empty?` #1651
- require `ISO8601DateTime` by default #1660
- Support `extend` in the parser #1620
- Improve generator to have nicer error handling in development
### Bug fixes
- Fix `@skip`/`@include` with default value of `false` #1617
- Fix lists of abstract types with promises #1613
- Don't check the type of `nil` when it's in a list #1610
- Fix NoMethodError when `variables: nil` is passed to `execute(...)` #1661
- Objects returned from `Schema.unauthorized_objects` are properly wrapped by their type proxies #1662
## 1.8.4 (21 June 2018)
### New features
- Add class-based definitions for Relay types #1568
- Add a built-in auth system #1494
### Bug fixes
- Properly rescue coercion errors in variable values #1602
## 1.8.3 (14 June 2018)
### New features
- Add an ISO 8601 DateTime scalar: `Types::ISO8601DateTime`. #1566
- Use classes under the hood for built-in scalars. These are now accessible via `Types::` namespace. #1565
- Add `possible_types` helpers to abstract types #1580
### Bug fixes
- Fix `Language::Visitor` when visiting `InputObjectTypeDefinition` nodes to include child `Directive` nodes. #1584
- Fix an issue preventing proper subclassing of `TimeoutMiddleware`. #1579
- Fix `graphql:interface` generator such that it generates working code. #1577
- Update the description of auto-generated `before` and `after` arguments to better describe their input type. #1572
- Add `Language::Nodes::DirectiveLocation` AST node to represent directive locations in directive definitions. #1564
## 1.8.2 (6 June 2018)
### Breaking changes
- `Schema::InputObject#to_h` recursively transforms hashes to underscorized, symbolized keys. #1555
### New features
- Generators create class-based types #1562
- `Schema::InputObject#to_h` returns a underscorized, symbolized hash #1555
### Bug fixes
- Support `default_mask` in class-based schemas #1563
- Fix null propagation for list types #1558
- Validate unique arguments in queries #1557
- Fix `RelayClassicMutation`s with no arguments #1543
## 1.8.1 (1 June 2018)
### Breaking changes
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
### New features
- `GraphQL::ExecutionError.new` accepts an `extensions:` option which will be merged into the `"extensions"` key in that error's JSON #1552
### Bug fixes
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
- Require that fields returning interfaces have selections made on them #1551
- Correctly mark introspection types and fields as `introspection?` #1535
- Remove unused introspection objects #1534
- use `object`/`context` in the upgrader instead of `@object`/`@context` #1529
- (Development) Don't require mongodb for non-mongo tests #1548
- Track position of union member nodes in the parser #1541
## 1.8.0 (17 May 2018)
`1.8.0` has been in prerelease for 6 months. See the prerelease changelog for change-by-change details. Here's a high-level changelog, followed by a detailed list of changes since the last prerelease.
### High-level changes
#### Breaking Changes
- GraphQL-Ruby is not tested on Ruby 2.1. #1070 Because Ruby 2.1 doesn't garbage collect Symbols, it's possible that GraphQL-Ruby will introduce a OOM vulnerability where unique symbols are dynamically created, for example, turning user input into Symbols. No instances of this are known in GraphQL-Ruby ... yet!
- `GraphQL::Delegate`, a duplicate of Ruby's `Forwardable`, was removed. Use `Forwardable` instead, and update your Ruby if you're on `2.4.0`, due to a performance regression in `Forwardable` in that version.
- `MySchema.subscriptions.trigger` asserts that its inputs are valid arguments #1400. So if you were previously passing invalid options there, you'll get an error. Remove those options.
#### New Features
- A new class-based API for schema definition. The old API is completely supported, but the new one is much nicer to use. If you migrate, some schema extensions may require a bit of extra work.
- Built-in support for Mongoid-backed Relay connections
- `.execute(variables: ...)` and `subscriptions.trigger` both accept Symbol-keyed hashes
- Lots of other small things around SDL parsing, tracing, runtime ... everything. Read the details below for a full list.
#### Bug Fixes
- Many, many bug fixes. See the detailed list if you're curious about specific bugs.
### Changes since `1.8.0.pre11`:
#### Breaking Changes
- `GraphQL::Schema::Field#initialize`'s signature changed to accept keywords and a block only. `type:`, `description:` and `name:` were moved to keywords. See `Field.from_options` for how the `field(...)` helper's arguments are merged to go to `Field.new`. #1508
#### New Features
- `Schema::Resolver` is a replacement for `GraphQL::Function` #1472
- Fix subscriptions with class-based schema #1478
- `Tracing::NewRelicTracing` accepts `set_transaction_name:` to use the GraphQL operation name as the NewRelic transaction name #1430
#### Bug fixes
- Backported `accepts_definition`s are inherited #1514
- Fix Schema generator's `resolve_type` method #1481
- Fix constant assignment warnings with interfaces including multiple other interfaces #1465
- InputObject types loaded from SDL have the proper AST node assigned to them #1512
## 1.8.0.pre11 (3 May 2018)
### Breaking changes
- `Schema::Mutation.resolve_mutation` was moved to an instance method; see changes to `Schema::RelayClassicMutation` in #1469 for an example refactor
- `GraphQL::Delegate` was removed, use Ruby's `Forwardable` instead (warning: bad performance on Ruby 2.4.0)
- `GraphQL::Schema::Interface` is a module, not a class #1372. To refactor, use a base module instead of a base class:
```ruby
module BaseInterface
include GraphQL::Schema::Interface
end
```
And include that in your interface types:
```ruby
module Reservable
include BaseInterface
field :reservations, ...
end
```
In object types, no change is required; use `implements` as before:
```ruby
class EventVenue < BaseObject
implements Reservable
end
```
### New features
- `GraphQL::Schema::Interface` is a module
- Support `prepare:` and `as:` argument options #1469
- First-class support for Mongoid connections #1452
- More type inspection helpers for class-based types #1446
- Field methods may call `super` to get the default behavior #1437
- `variables:` accepts symbol keys #1401
- Reprint any directives which were parsed from SDL #1417
- Support custom JSON scalars #1398
- Subscription `trigger` accepts symbol, underscored arguments and validates their presence #1400
- Mutations accept a `null(true | false)` setting to affect field nullability #1406
- `RescueMiddleware` uses inheritance to match errors #1393
- Resolvers may return a list of errors #1231
### Bug fixes
- Better error for anonymous class names #1459
- Input Objects correctly inherit arguments #1432
- Fix `.subscriptions` for class-based Schemas #1391
## 1.8.0.pre10 (4 Apr 2018)
### New features
- Add `Schema::Mutation` and `Schema::RelayClassicMutation` base classes #1360
### Bug fixes
- Fix using anonymous classes for field types #1358
## 1.8.0.pre9 (19 Mar 2018)
- New version number. (I needed this because I messed up build tooling for 1.8.0.pre8).
## 1.8.0.pre8 (19 Mar 2018)
### New Features
- Backport `accepts_definition` for configurations #1357
- Add `#owner` method to Schema objects
- Add `Interface.orphan_types` config for orphan types #1346
- Add `extras: :execution_errors` for `add_error` #1313
- Accept a block to `Schema::Argument#initialize` #1356
### Bug Fixes
- Support `cursor_encoder` #1357
- Don't double-count lazy/eager field time in Tracing #1321
- Fix camelization to support single leading underscore #1315
- Fix `.resolve_type` for Union and Interface classes #1342
- Apply kwargs before block in `Argument.from_dsl` #1350
## 1.8.0.pre7 (27 Feb 2018)
### New features
- Upgrader improvements #1305
- Support `global_id_field` for interfaces #1299
- Add `camelize: false` #1300
- Add readers for `context`, `object` and `arguments` #1283
- Replace `Schema.method_missing` with explicit whitelist #1265
## 1.8.0.pre6 (1 Feb 2018)
### New features
- Custom enum value classes #1264
### Bug fixes
- Properly print SDL type directives #1255
## 1.8.0.pre5 (1 Feb 2018)
### New features
- Upgrade argument access with the upgrader #1251
- Add `Schema#find(str)` for finding schema members by name #1232
### Bug fixes
- Fix `Schema.max_complexity` #1246
- Support cyclical connections/edges #1253
## 1.8.0.pre4 (18 Jan 2018)
### Breaking changes
- `Type.fields`, `Field.arguments`, `Enum.values` and `InputObject.arguments` return a Hash instead of an Array #1222
### New features
- By default, fields try hash keys which match their name, as either a symbol or a string #1225
- `field do ... end` instance_evals on the Field instance, not a FieldProxy #1227
- `[T, null: true]` creates lists with nullable items #1229
- Upgrader improvements #1223
### Bug fixes
- Don't require `parser` unless the upgrader is run #1218
## 1.8.0.pre3 (12 Jan 2018)
### New Features
- Custom `Context` classes for class-based schemas #1161
- Custom introspection for class-based schemas #1170
- Improvements to upgrader tasks and internals #1151, #1178, #1212
- Allow description inside field blocks #1175
## 1.8.0.pre2 (29 Nov 2017)
### New Features
- Add `rake graphql:upgrade[app/graphql]` for automatic upgrade #1110
- Automatically camelize field names and argument names #1143, #1126
- Improved error message when defining `name` instead of `graphql_name` #1104
### Bug fixes
- Fix list wrapping when value is `nil` #1117
- Fix ArgumentError typo #1098
## 1.8.0.pre1 (14 Nov 2017)
### Breaking changes
- Stop official support for Ruby 2.1 #1070
### New features
- Add class-based schema definition API #1037
## 1.7.14 (4 Apr 2018)
### New features
- Support new IDL spec for `&` for interfaces #1304
- Schema members built from IDL have an `#ast_node` #1367
### Bug fixes
- Fix paging backwards with `hasNextPage` #1319
- Add hint for `orphan_types` in error message #1380
- Use an empty hash for `result` when a query has unhandled errors #1382
## 1.7.13 (28 Feb 2018)
### Bug fixes
- `Schema#as_json` returns a hash, not a `GraphQL::Query::Result` #1288
## 1.7.12 (13 Feb 2018)
### Bug fixes
- `typed_children` should always return a Hash #1278
## 1.7.11 (13 Feb 2018)
### Bug fixes
- Fix compatibility of `irep_node.typed_children` on leaf nodes #1277
## 1.7.10 (13 Feb 2018)
### Breaking Changes
- Empty selections (`{ }`) are invalid in the GraphQL spec, but were previously allowed by graphql-ruby. They now return a parse error. #1268
### Bug fixes
- Fix error when inline fragments are spread on scalars #1268
- Fix printing SDL when types have interfaces and directives #1255
## 1.7.9 (1 Feb 2018)
## New Features
- Support block string inputs #1219
## Bug fixes
- Fix deprecation regression in schema printer #1250
- Fix resource names in DataDog tracing #1208
- Fix passing `context` to multiplex in `Query#result` #1200
## 1.7.8 (11 Jan 2018)
### New features
- Refactor `Schema::Printer` to use `Language::Printer` #1159
- Add `ArgumentValue#default_used?` and `Arguments#default_used?` #1152
### Bug fixes
- Fix Scout Tracing #1187
- Call `#inspect` for `EnumType::UnresolvedValueError` #1179
- Parse empty field sets in IDL parser #1145
## 1.7.7 (29 Nov 2017)
### New features
- `Schema#to_document` returns a `Language::Nodes::Document` #1134
- Add `trace_scalars` and `trace: true|false` to monitoring #1103
- Add `Tracing::DataDogPlatform` monitoring #1129
- Support namespaces in `rails g graphql:function` and `:loader` #1127
- Support `serializer:` option for `ActionCableSubscriptions` #1085
### Bug fixes
- Properly count the column after a closing quote #1136
- Fix default value input objects in `Schema.from_definition` #1135
- Fix `rails destroy graphql:mutation` #1119
- Avoid unneeded query in RelationConnection with Sequel #1101
- Improve & document instrumentation stack behavior #1101
## 1.7.6 (13 Nov 2017)
### Bug fixes
- Serialize symbols in with `GraphQL::Subscriptions::Serialize` #1084
## 1.7.5 (7 Nov 2017)
### Breaking changes
- Rename `Backtrace::InspectResult#inspect` to `#inspect_result` #1022
### New features
- Improved website search with Algolia #934
- Support customized generator directory #1047
- Recursively serialize `GlobalID`-compliant objects in Arrays and hashes #1030
- Add `Subscriptions#build_id` helper #1046
- Add `#non_null?` and `#list?` helper methods to type objects #1054
### Bug fixes
- Fix infinite loop in query instrumentation when error is raised #1074
- Don't try to trace error when it's not raised during execution
- Improve validation of query variable definitions #1073
- Fix Scout tracing module load order #1064
## 1.7.4 (9 Oct 2017)
### Deprecations
- `GraphQL::Tracing.install` is deprecated, use schema-local or query-local tracers instead #996
### New features
- Add monitoring plugins for AppSignal, New Relic, Scout and Skylight #994, #1013
- Custom coercion errors for custom scalars #988
- Extra `options` for `GraphQL::ExecutionError` #1002
- Use `GlobalID` for subscription serialization when available #1004
- Schema- and query-local, threadsafe tracers #996
### Bug fixes
- Accept symbol-keyed arguments to `.trigger` #1009
## 1.7.3 (20 Sept 2017)
### Bug fixes
- Fix arguments on `Query.__type` field #978
- Fix `Relay::Edge` objects in `Backtrace` tables #975
## 1.7.2 (20 Sept 2017)
### Bug fixes
- Correctly skip connections that return `ctx.skip` #972
## 1.7.1 (18 Sept 2017)
### Bug fixes
- Properly release changes from 1.7.0
## 1.7.0 (18 Sept 2017)
### Breaking changes
- `GraphQL::Result` is the returned from GraphQL execution. #898 `Schema#execute` and `Query#result` both return a `GraphQL::Result`. It implements Hash-like methods to preserve compatibility.
### New features
- `puts ctx.backtrace` prints out a GraphQL backtrace table #946
- `GraphQL::Backtrace.enable` wraps unhandled errors with GraphQL backtraces #946
- `GraphQL::Relay::ConnectionType.bidrectional_pagination = true` turns on _true_ bi-directional pagination checks for `hasNextPage`/`hasPreviousPage` fields. This will become the default behavior in a future version. #960
- Field arguments may be accessed as methods on the `args` object. This is an alternative to `#[]` syntax which provides did-you-mean behavior instead of returning `nil` on a typo. #924 For example:
```ruby
# using hash syntax:
args[:limit] # => 10
args[:limittt] # => nil
# using method syntax:
args.limit # => 10
args.limittt # => NoMethodError
```
The old syntax is _not_ deprecated.
- Improvements to schema filters #919
- If a type is not referenced by anything, it's hidden
- If a type is an abstract type, but has no visible members, it's hidden
- `GraphQL::Argument.define` builds re-usable arguments #948
- `GraphQL::Subscriptions` provides hooks for subscription platforms #672
- `GraphQL::Subscriptions::ActionCableSubscriptions` implements subscriptions over ActionCable #672
- More runtime values are accessble from a `ctx` object #923 :
- `ctx.parent` returns the `ctx` from the parent field
- `ctx.object` returns the current `obj` for that field
- `ctx.value` returns the resolved GraphQL value for that field
These can be used together, for example, `ctx.parent.object` to get the parent object.
- `GraphQL::Tracing` provides more hooks into gem internals for performance monitoring #917
- `GraphQL::Result` provides access to the original `query` and `context` after executing a query #898
### Bug fixes
- Prevent passing _both_ query string and parsed document to `Schema#execute` #957
- Prevent invalid names for types #947
## 1.6.8 (8 Sept 2017)
### Breaking changes
- Validate against EnumType value names to match `/^[_a-zA-Z][_a-zA-Z0-9]*$/` #915
### New features
- Use stdlib `forwardable` when it's not Ruby 2.4.0 #926
- Improve `UnresolvedTypeError` message #928
- Add a default field to the Rails generated mutation type #922
### Bug fixes
- Find types via directive arguments when traversing the schema #944
- Assign `#connection?` when building a schema from IDL #941
- Initialize `@edge_class` to `nil` #942
- Disallow invalid enum values #915
- Disallow doubly-nested non-null types #916
- Fix `Query#selected_operation_name` when no selections are present #899
- Fix needless `COUNT` query for `hasNextPage` #906
- Fix negative offset with `last` argument #907
- Fix line/col for `ArgumentsAreDefined` validation #890
- Fix Sequel error when limit is `0` #892
## 1.6.7 (11 Aug 2017)
### New features
- Add `GraphQL.parse_file` and `AbstractNode#filename` #873
- Support `.graphql` filepaths with `Schema.from_definition` #872
### Bug fixes
- Fix variable usage inside non-null list #888
- Fix unqualified usage of ActiveRecord::Relation #885
- Fix `FieldsWillMerge` handling of equivalent input objects
- Fix to call `prepare:` on nested input types
## 1.6.6 (14 Jul 2017)
### New features
- Validate `graphql-pro` downloads with `rake graphql:pro:validate[$VERSION]` #846
### Bug fixes
- Remove usage of Rails-only `Array.wrap` #840
- Fix `RelationConnection` to count properly when relation contains an alias #838
- Print name of Enum type when a duplicate value is added #843
## 1.6.5 (13 Jul 2017)
### Breaking changes
- `Schema#types[](type_name)` returns `nil` when there's no type named `type_name` (it used to raise `RuntimeError`). To get an error for missing types, use `.fetch` instead, for example:
```ruby
# Old way:
MySchema.types[type_name] # => may raise RuntimeError
# New way:
MySchema.types.fetch(type_name) # => may raise KeyError
```
- Schema build steps happen in one pass instead of two passes #819 . This means that `instrument(:field)` hooks may not access `Schema#types`, `Schema#possible_types` or `Schema#get_field`, since the underlying data hasn't been prepared yet. There's not really a clear upgrade path here. It's a bit of a mess. If you're affected by this, feel free to open an issue and we'll try to find something that works!
### Deprecations
- `Schema#resolve_type` is now called with `(abstract_type, obj, ctx)` instead of `(obj, ctx)` #834 . To update, add an unused parameter to the beginning of your `resolve_type` hook:
```ruby
MySchema = GraphQL::Schema.define do
# Old way:
resolve_type ->(obj, ctx) { ... }
# New way:
resolve_type ->(type, obj, ctx) { ... }
end
```
### New features
- `rails g graphql:mutation` will add Mutation boilerplate if it wasn't added already #812
- `InterfaceType` and `UnionType` both accept `resolve_type ->(obj, ctx) { ... }` functions for type-specific resolution. This function takes precedence over `Schema#resolve_type` #829 #834
- `Schema#resolve_type` is called with three arguments, `(abstract_type, obj, ctx)`, so you can distinguish object type based on interface or union.
- `Query#operation_name=` may be assigned during query instrumentation #833
- `query.context.add_error(err)` may be used to add query-level errors #833
### Bug fixes
- `argument(...)` DSL accepts custom keywords #809
- Use single-query `max_complexity` overrides #812
- Return a client error when `InputObjectType` receives an array as input #803
- Properly handle raised errors in `prepare` functions #805
- Fix using `as` and `prepare` in `argument do ... end` blocks #817
- When types are added to the schema with `instrument(:field, ...)`, make sure they're in `Schema#types` #819
- Raise an error when duplicate `EnumValue` is created #831
- Properly resolve all query levels breadth-first when using `lazy_resolve` #835
- Fix tests to run on PostgresQL; Run CI on PostgresQL #814
- When no query string is present, return a client error instead of raising `ArgumentError` #833
- Properly validate lists containing variables #824
## 1.6.4 (20 Jun 2017)
### New features
- `Schema.to_definition` sorts fields and arguments alphabetically #775
- `validate: false` skips static validations in query execution #790
### Bug fixes
- `graphql:install` adds `operation_name: params[:operationName]` #786
- `graphql:install` skips `graphiql-rails` for API-only apps #772
- `SerialExecution` calls `.is_a?(Skip)` to avoid user-defined `#==` methods #794
- `prepare:` functions which return `ExecutionError` are properly handled when default values are present #801
## 1.6.3 (7 Jun 2017)
### Bug fixes
- Run multiplex instrumentation when running a single query with a legacy execution strategy #766
- Check _each_ strategy when looking for overridden execution strategy #765
- Correctly wrap `Method`s with BackwardsCompatibility #763
- Various performance improvements #764
- Don't call `#==(other)` on user-provided objects (use `.is_a?` instead) #761
- Support lazy object from custom connection `#edge_nodes` #762
- If a lazy field returns an invalid null, stop evaluating its siblings #767
## 1.6.2 (2 Jun 2017)
### New features
- `Schema.define { default_max_page_size(...) }` provides a Connection `max_page_size` when no other is provided #752
- `Schema#get_field(type, field)` accepts a string type name #756
- `Schema.define { rescue_from(...) }` accepts multiple error classes for the handler #758
### Bug fixes
- Use `*_execution_strategy` when executing a single query (doesn't support `Schema#multiplex`) #755
- Fix NameError when `ActiveRecord` isn't loaded #747
- Fix `Query#mutation?` etc to support lazily-loaded AST #754
## 1.6.1 (28 May 2017)
### New Features
- `Query#selected_operation_name` returns the operation to execute, even if it was inferred (not provided as `operation_name:`) #746
### Bug fixes
- Return `nil` from `Query#operation_name` if no `operation_name:` was provided #746
## 1.6.0 (27 May 2017)
### Breaking changes
- `InternalRepresentation::Node#return_type` will now return the wrapping type. Use `return_type.unwrap` to access the old value #704
- `instrument(:query, ...)` instrumenters are applied as a stack instead of a queue #735. If you depend on queue-based behavior, move your `before_query` and `after_query` hooks to separate instrumenters.
- In a `Relay::Mutation`, Raising or returning a `GraphQL::Execution` will nullify the mutation field, not the field's children. #731
- `args.to_h` returns a slightly different hash #714
- keys are always `String`s
- if an argument is aliased with `as:`, the alias is used as the key
- `InternalRepresentation::Node#return_type` includes the original "wrapper" types (non-null or list types), call `.unwrap` to get the inner type #20
```ruby
# before
irep_node.return_type
# after
irep_node.return_type.unwrap
```
### Deprecations
- Argument `prepare` functions which take one argument are deprecated #730
```ruby
# before
argument :id, !types.ID, prepare: ->(val) { ... }
# after
argument :id, !types.ID, prepare: ->(val, ctx) { ... }
```
### New features
- `Schema#multiplex(queries)` runs multiple queries concurrently #691
- `GraphQL::RakeTask` supports dumping the schema to IDL or JSON #687
- Improved support for `Schema.from_definition` #699 :
- Custom scalars are supported with `coerce_input` and `coerce_result` functions
- `resolve_type` function will be used for abstract types
- Default resolve behavior is to check `obj` for a method and call it with 0, 1, or 2 arguments.
- `ctx.skip` may be returned from field resolve functions to exclude the field from the response entirely #688
- `instrument(:field, ..., after_built_ins: true)` to apply field instrumentation after Relay wrappers #740
- Argument `prepare` functions are invoked with `(val, ctx)` (previously, it was only `(val)`) #730
- `args.to_h` returns stringified, aliased arguments #714
- `ctx.namespace(:my_namespace)` provides namespaced key-value storage #689
- `GraphQL::Query` can be initialized without a query_string; it can be added after initialization #710
- Improved filter support #713
- `Schema.execute(only:, except:)` accept a callable _or_ an array of callables (multiple filters)
- Filters can be added to a query via `Query#merge_filters(only:, except:)`. You can add a filter to every query by merging it in during query instrumentation.
### Bug fixes
- Correctly apply cursors and `max_page_size` in `Relay::RelationConnection` and `Relay::ArrayConnection` #728
- Nullify a mutation field when it raises or returns an error #731
## 1.5.14 (27 May 2017)
### New features
- `UniqueWithinType` Relay ID generator supports `-` in the ID #742
- `assign_metadata_key` assigns `true` when the definition method is called without arguments #724
- Improved lexer performance #737
### Bug fixes
- Assign proper `parent` when a `connection` resolve returns a promise #736
## 1.5.13 (11 May 2017)
- Fix raising `ExecutionError` inside mutation resolve functions (it nullifies the field) #722
## 1.5.12 (9 May 2017)
- Fix returning `nil` from connection resolve functions (now they become `null`) #719
- Fix duplicate AST nodes when merging fragments #721
## 1.5.11 (8 May 2017)
### New features
- `Schema.from_definition` accepts a `parser:` option (to work around lack of schema parser in `graphql-libgraphqlparser`) #712
- `Query#internal_representation` exposes an `InternalRepresentation::Document` #701
- Update generator usage of `graphql-batch` #697
### Bug fixes
- Handle fragments with the same name as operations #706
- Fix type generator: ensure type name is camelized #718
- Fix `Query#operation_name` to return the operation name #707
- Fix pretty-print of non-null & list types #705
- Fix single input objects passed to list-type arguments #716
## 1.5.10 (25 Apr 2017)
### New features
- Support Rails 5.1 #693
- Fall back to `String#encode` for non-UTF-8/non-ASCII strings #676
### Bug Fixes
- Correctly apply `Relay::Mutation`'s `return_field ... property:` argument #692
- Handle Rails 5.1's `ActionController::Parameters` #693
## 1.5.9 (19 Apr 2017)
### Bug Fixes
- Include instrumentation-related changes in introspection result #681
## 1.5.8 (18 Apr 2017)
### New features
- Use Relay PageInfo descriptions from graphql-js #673
### Bug Fixes
- Allow fields with different arguments when fragments are included within inline fragments of non-overlapping types #680
- Run `lazy_resolve` instrumentation for `connection` fields #679
## 1.5.7 (14 Apr 2017)
### Bug fixes
- `InternalRepresentation::Node#definition` returns `nil` instead of raising NoMethodError for operation fields #675
- `Field#function` is properly populated for fields derived from `GraphQL::Function`s #674
## 1.5.6 (9 Apr 2017)
## Breaking Changes
- Returned strings which aren't encoded as UTF-8 or ASCII will raise `GraphQL::StringEncodingError` instead of becoming `nil` #661
To preserve the previous behavior, Implement `Schema#type_error` to return `nil` for this error, eg:
```ruby
GraphQL::Schema.define do
type_error ->(err, ctx) {
case err
# ...
when GraphQL::StringEncodingError
nil
end
}
```
- `coerce_non_null_input` and `validate_non_null_input` are private #667
## Deprecations
- One-argument `coerce_input` and `coerce_result` functions for custom scalars are deprecated. #667 Those functions now accept a second argument, `ctx`.
```ruby
# From
->(val) { val.to_i }
# To:
->(val, ctx) { val.to_i }
```
- Calling `coerce_result`, `coerce_input`, `valid_input?` or `validate_input` without a `ctx` is deprecated. #667 Use `coerce_isolated_result` `coerce_isolated_input`, `valid_isolated_input?`, `validate_input` to explicitly bypass `ctx`.
## New Features
- Include `#types` in `GraphQL::Function` #654
- Accept `prepare:` function for arguments #646
- Scalar coerce functions receive `ctx` #667
## Bug Fixes
- Properly apply default values of `false` #658
- Fix application of argument options in `GraphQL::Relay::Mutation` #660
- Support concurrent-ruby `>1.0.0` #663
- Only raise schema validation errors on `#execute` to avoid messing with Rails constant loading #665
## 1.5.5 (31 Mar 2017)
### Bug Fixes
- Improve threadsafety of `lazy_resolve` cache, use `Concurrent::Map` if it's available #631
- Properly handle unexpeced input objects #638
- Handle errors during definition by preseriving the definition #632
- Fix `nil` input for nullable list types #637, #639
- Handle invalid schema IDL with a validation error #647
- Properly serialize input object default values #635
- Fix `as:` on mutation `input_field` #650
- Fix null propagation for `nil` members of non-null list types #649
## 1.5.4 (22 Mar 2017)
### Breaking Changes
- Stop supporting deprecated one-argument schema masks #616
### Bug Fixes
- Return a client error for unknown variable types when default value is provided or when directives are present #627
- Fix validation performance regression on nested abstract fragment conditions #622, #624
- Put back `InternalRepresentation::Node#parent` and fix it for fragment fields #621
- Ensure enum names are strings #619
## 1.5.3 (20 Mar 2017)
### Bug Fixes
- Fix infinite loop triggered by user input. #620 This query would cause an infinite loop:
```graphql
query { ...frag }
fragment frag on Query { __typename }
fragment frag on Query { ...frag }
```
- Validate fragment name uniqueness #618
## 1.5.2 (16 Mar 2017)
### Breaking Changes
- Parse errors are no longer raised to the application. #607 Instead, they're returned to the client in the `"errors"` key. To preserve the previous behavior, you can implement `Schema#parse_error` to raise the error:
```ruby
MySchema = GraphQL::Schema.define do
# ...
parse_error ->(err, ctx) { raise(err) }
end
```
### New Features
- Add `graphq:enum` generator #611
- Parse errors are returned to the client instead of raised #607
### Bug Fixes
- Handle negative cursor pagination args as `0` #612
- Properly handle returned `GraphQL::ExecutionError`s from connection resolves #610
- Properly handle invalid nulls in lazy scalar fields #609
- Properly handle invalid input objects passed to enum arguments #604
- Fix introspection response of enum default values #605
- Allow `Schema.from_definition` default resolver hashes to have defaults #608
## 1.5.1 (12 Mar 2017)
### Bug fixes
- Fix rewrite performance regressions from 1.5.0 #599
- Remove unused `GraphQL::Execution::Lazy` initialization API #597
## 1.5.0 (10 Mar 2017), yanked
### Breaking changes
- _Only_ UTF-8-encoded strings will be returned by `String` fields. Strings with other encodings (or objects whose `#to_s` method returns a string with a different encoding) will return `nil` instead of that string. #517
To opt into the _previous_ behavior, you can modify `GraphQL::STRING_TYPE`:
```ruby
# app/graphql/my_schema.rb
# Restore previous string behavior:
GraphQL::STRING_TYPE.coerce_result = ->(value) { value.to_s }
MySchema = GraphQL::Schema.define { ... }
```
- Substantial changes to the internal query representation (#512, #536). Query analyzers may notice some changes:
- Nodes skipped by directives are not visited
- Nodes are always on object types, so `Node#owner_type` always returns an object type. (Interfaces and Unions are replaced with concrete object types which are valid in the current scope.)
See [changes to `Analysis::QueryComplexity`](https://github.com/rmosolgo/graphql-ruby/compare/v1.4.5...v1.5.0#diff-8ff2cdf0fec46dfaab02363664d0d201) for an example migration. Here are some other specific changes:
- Nodes are tracked on object types only, not interface or union types
- Deprecated, buggy `Node#children` and `Node#path` were removed
- Buggy `#included` was removed
- Nodes excluded by directives are entirely absent from the rewritten tree
- Internal `InternalRepresentation::Selection` was removed (no longer needed)
- `Node#spreads` was replaced by `Node#ast_spreads` which returns a Set
### New features
- `Schema#validate` returns a list of errors for a query string #513
- `implements ...` adds interfaces to object types _without_ inherit-by-default #548, #574
- `GraphQL::Relay::RangeAdd` for implementing `RANGE_ADD` mutations #587
- `use ...` definition method for plugins #565
- Rails generators #521, #580
- `GraphQL::Function` for reusable resolve behavior with arguments & return type #545
- Support for Ruby 2.4 #475
- Relay `node` & `nodes` field can be extended with a custom block #552
- Performance improvements:
- Resolve fragments only once when validating #504
- Reuse `Arguments` objects #500
- Skip needless `FieldResult`s #482
- Remove overhead from `ensure_defined` #483
- Benchmark & Profile tasks for gem maintenance #520, #579
- Fetch `has_next_page` while fetching items in `RelationConnection` #556
- Merge selections on concrete object types ahead of time #512
- Support runnable schemas with `Schema.from_definition` #567, #584
### Bug fixes
- Support different arguments on non-overlapping typed fragments #512
- Don't include children of `@skip`ped nodes when parallel branches are not skipped #536
- Fix offset in ArrayConnection when it's larger than the array #571
- Add missing `frozen_string_literal` comments #589
## 1.4.5 (6 Mar 2017)
### Bug Fixes
- When an operation name is provided but no such operation is present, return an error (instead of executing the first operation) #563
- Require unique operation names #563
- Require selections on root type #563
- If a non-null field returns `null`, don't resolve any more sibling fields. #575
## 1.4.4 (17 Feb 2017)
### New features
- `Relay::Node.field` and `Relay::Node.plural_field` accept a custom `resolve:` argument #550
- `Relay::BaseConnection#context` provides access to the query context #537
- Allow re-assigning `Field#name` #541
- Support `return_interfaces` on `Relay::Mutation`s #533
- `BaseType#to_definition` stringifies the type to IDL #539
- `argument ... as:` can be used to alias an argument inside the resolve function #542
### Bug fixes
- Fix negative offset from cursors on PostgresQL #510
- Fix circular dependency issue on `.connection_type`s #535
- Better error when `Relay::Mutation.resolve` doesn't return a Hash
## 1.4.3 (8 Feb 2017)
### New features
- `GraphQL::Relay::Node.plural_field` finds multiple nodes by UUID #525
### Bug fixes
- Properly handle errors from lazy mutation results #528
- Encode all parsed strings as UTF-8 #516
- Improve error messages #501 #519
## 1.4.2 (23 Jan 2017)
### Bug fixes
- Absent variables aren't present in `args` (_again_!) #494
- Ensure definitions were executed when accessing `Field#resolve_proc` #502 (This could have caused errors when multiple instrumenters modified the same field in the schema.)
## 1.4.1 (16 Jan 2017)
### Bug fixes
- Absent variables aren't present in `args` #479
- Fix grouped ActiveRecord relation with `last` only #476
- `Schema#default_mask` & query `only:`/`except:` are combined, not overriden #485
- Root types can be hidden with dynamic filters #480
## 1.4.0 (8 Jan 2017)
### Breaking changes
### Deprecations
- One-argument schema filters are deprecated. Schema filters are now called with _two_ arguments, `(member, ctx)`. #463 To update, add a second argument to your schema filter.
- The arity of middleware `#call` methods has changed. Instead of `next_middleware` being the last argument, it is passed as a block. To update, call `yield` to continue the middleware chain or use `&next_middleware` to capture `next_middleware` into a local variable.
```ruby
# Previous:
def call(*args, next_middleware)
next_middleware.call
end
# Current
def call(*args)
yield
end
# Or
def call(*args, &next_middleware)
next_middleware.call
end
```
### New features
- You can add a `nodes` field directly to a connection. #451 That way you can say `{ friends { nodes } }` instead of `{ freinds { edges { node } } }`. Either pass `nodes_field: true` when defining a custom connection type, for example:
```ruby
FriendsConnectionType = FriendType.define_connection(nodes_field: true)
```
Or, set `GraphQL::Relay::ConnectionType.default_nodes_field = true` before defining your schema, for example:
```ruby
GraphQL::Relay::ConnectionType.default_nodes_field = true
MySchema = GraphQL::Schema.define { ... }
```
- Middleware performance was dramatically improved by reducing object allocations. #462 `next_middleware` is now passed as a block. In general, [`yield` is faster than calling a captured block](https://github.com/JuanitoFatas/fast-ruby#proccall-and-block-arguments-vs-yieldcode).
- Improve error messages for wrongly-typed variable values #423
- Cache the value of `resolve_type` per object per query #462
- Pass `ctx` to schema filters #463
- Accept whitelist schema filters as `only:` #463
- Add `Schema#to_definition` which accepts `only:/except:` to filter the schema when printing #463
- Add `Schema#default_mask` as a default `except:` filter #463
- Add reflection methods to types #473
- `#introspection?` marks built-in introspection types
- `#default_scalar?` marks built-in scalars
- `#default_relay?` marks built-in Relay types
- `#default_directive?` marks built-in directives
### Bug fixes
- Fix ArrayConnection: gracefully handle out-of-bounds cursors #452
- Fix ArrayConnection & RelationConnection: properly handle `last` without `before` #362
## 1.3.0 (8 Dec 2016)
### Deprecations
- As per the spec, `__` prefix is reserved for built-in names only. This is currently deprecated and will be invalid in a future version. #427, #450
### New features
- `Schema#lazy_resolve` allows you to define handlers for a second pass of resolution #386
- `Field#lazy_resolve` can be instrumented to track lazy resolution #429
- `Schema#type_error` allows you to handle `InvalidNullError`s and `UnresolvedTypeErrors` in your own way #416
- `Schema#cursor_encoder` can be specified for transforming cursors from built-in Connection implementations #345
- Schema members `#dup` correctly: they shallowly copy their state into new instances #444
- `Query#provided_variables` is now public #430
### Bug fixes
- Schemas created from JSON or strings with custom scalars can validate queries (although they still can't check if inputs are valid for those custom scalars) #445
- Always use `quirks_mode: true` when serializing values (to support non-stdlib `JSON`s) #449
- Calling `#redefine` on a Schema member copies state outside of previous `#define` blocks (uses `#dup`) #444
## 1.2.6 (1 Dec 2016)
### Bug fixes
- Preserve connection behaviors after `redefine` #421
- Implement `respond_to_missing?` on `DefinedObjectProxy` (which is `self` inside `.define { ... }`) #414
## 1.2.5 (22 Nov 2016)
### Breaking changes
- `Visitor` received some breaking changes, though these are largely-private APIs (#401):
- Global visitor hooks (`Visitor#enter` and `Visitor#leave`) have been removed
- Returning `SKIP` from a visitor hook no longer skips sibling nodes
### New features
- `Schema#instrument` may be called outside of `Schema.define` #399
- Validation: assert that directives on a node are unique #409
- `instrument(:query)` hooks are executed even if the query raises an error #412
### Bug fixes
- `Mutation#input_fields` should trigger lazy definition #392
- `ObjectType#connection` doesn't modify the provided `GraphQL::Field` #411
- `Mutation#resolve` may return a `GraphQL::ExecutionError` #405
- `Arguments` can handle nullable arguments passed as `nil` #410
## 1.2.4 (14 Nov 2016)
### Bug fixes
- For invalid enum values, print the enum name in the error message (not a Ruby object dump) #403
- Improve detection of invalid UTF-8 escapes #394
## 1.2.3 (14 Nov 2016)
### Bug fixes
- `Lexer` previous token should be a local variable, not a method attribute #396
- `Arguments` should wrap values according to their type, not their value #398
## 1.2.2 (7 Nov 2016)
### New features
- `Schema.execute` raises an error if `variables:` is a string
### Bug fixes
- Dynamic fields `__schema`, `__type` and `__typename` are properly validated #391
## 1.2.1 (7 Nov 2016)
### Bug fixes
- Implement `Query::Context#strategy` and `FieldResolutionContext#strategy` to support GraphQL::Batch #382
## 1.2.0 (7 Nov 2016)
### Breaking changes
- A breaking change from 1.1.0 was reverted: two-character `"\\u"` _is_ longer treated as the Unicode escape character #372
- Due to the execution bug described below, the internal representation of a query has changed. Although `Node` responds to the same methods, tree is built differently and query analyzers visit it differently. #373, #379
The difference is in cases like this:
```graphql
outer {
... on A { inner1 { inner2 } }
... on B { inner1 { inner3 } }
}
```
Previously, visits would be:
- `outer`, which has one child:
- `inner1`, which has two definitions (one on `A`, another on `B`), then visit its two `children`:
- `inner2` which has one definition (on the return type of `inner1`)
- `inner3` which has one definition (on the return type of `inner1`)
This can be wrong for some cases. For example, if `A` and `B` are mutually exclusive (both object types, or union types with no shared members), then `inner2` and `inner3` will never be executed together.
Now, the visit goes like this:
- `outer` which has two entries in `typed_children`, one on `A` and another on `B`. Visit each `typed_chidren` branch:
- `inner1`, then its one `typed_children` branch:
- `inner2`
- `inner1`, then its one `typed_children` branch:
- `inner3`
As you can see, we visit `inner1` twice, once for each type condition. `inner2` and `inner3` are no longer visited as siblings. Instead they're visited as ... cousins? (They share a grandparent, not a parent.)
Although `Node#children` is still present, it may not contain all children actually resolved at runtime, since multiple `typed_children` branches could apply to the same runtime type (eg, two branches on interface types can apply to the same object type). To track all children, you have to do some bookkeeping during visitation, see `QueryComplexity` for an example.
You can see PR #373 for how built-in analyzers were changed to reflect this.
### Deprecations
- `InternalRepresentation::Node#children` and `InternalRepresentation::Node#definitions` are deprecated due to the bug described below and the breaking change described above. Instead, use `InternalRepresentation::Node#typed_children` and `InternalRepresentation::Node#defininition`. #373
### New features
- `null` support for the whole library: as a query literal, variable value, and argument default value. To check for the presence of a nullable, use `Arguments#key?` #369
- `GraphQL::Schema::UniqueWithinType.default_id_separator` may be assigned to a custom value #381
- `Context#add_error(err)` may be used to add a `GraphQL::ExecutionError` to the response's `"errors"` key (and the resolve function can still return a value) #367
- The third argument of `resolve` is now a `FieldResolutionContext`, which behaves just like a `Query::Context`, except that it is not modified during query execution. This means you can capture a reference to that context and access some field-level details after the fact: `#path`, `#ast_node`, `#irep_node`. (Other methods are delegated to the underlying `Query::Context`) #379
- `TimeoutMiddleware`'s second argument is a _proxied_ query object: it's `#context` method returns the `FieldResolutionContext` (see above) for the timed-out field. Other methods are delegated to the underlying `Query` #379
### Bug fixes
- Fix deep selection merging on divergently-typed fragments. #370, #373, #379 Previously, nested selections on different fragments were not distinguished. Consider a case like this:
```graphql
... on A { inner1 { inner2 } }
... on B { inner1 { inner3 } }
```
Previously, an object of type `A` would resolve `inner1`, then the result would receive _both_ `inner2` and `inner3`. The same was true for an object of type `B`.
Now, those are properly distinguished. An object of type `A` resolves `inner1`, then its result receives `inner2`. An object of type `B` receives `inner1`, then `inner3`.
## 1.1.0 (1 Nov 2016)
### Breaking changes
- Two-character `"\\u"` is no longer treated as the Unicode escape character, only the Unicode escape character `"\u"` is treated that way. (This behavior was a bug, the migration path is to use the Unicode escape character.) #366
- `GraphQL::Language::ParserTests` was removed, use `GraphQL::Compatibility` instead. #366
- Non-null arguments can't be defined with default values, because those values would never be used #361
### New features
- `Schema.from_definition(definition_string)` builds a `GraphQL::Schema` out of a schema definition. #346
- Schema members (types, fields, arguments, enum values) can be hidden on a per-query basis with the `except:` option #300
- `GraphQL::Compatibility` contains `.build_suite` functions for testing user-provided parsers and execution strategies with GraphQL internals. #366
- Schema members respond to `#redefine { ... }` for making shallow copies with extended definitions. #357
- `Schema#instrument` provides an avenue for observing query and field resolution with no overhead.
- Some `SerialExecution` objects were converted to functions, resulting in a modest performance improvement for query resolution.
### Bug fixes
- `NonNullType` and `ListType` have no name (`nil`), as per the spec #355
- Non-null arguments can't be defined with default values, because those values would never be used #361
## 1.0.0 (25 Oct 2016)
### Breaking changes
- `validate: false` option removed from `Schema.execute` (it didn't work anyways) #338
- Some deprecated methods were removed: #349
- `BaseConnection#object` was removed, use `BaseConnection#nodes`
- `BaseConnection.connection_for_items` was removed, use `BaseConnection#connection_for_nodes`
- Two-argument resolve functions for `Relay::Mutation`s are not supported, use three arguments instead: `(root_obj, input, ctx)`
- `Schema.new` no longer accepts initialization options, use `Schema.define` instead
- `GraphQL::ObjectType::UnresolvedTypeError` was removed, use `GraphQL::UnresolvedTypeError` instead
- Fragment type conditions should be parsed as `TypeName` nodes, not strings. (Users of `graphql-libgraphqlparser` should update to `1.0.0` of that gem.) #342
### New Features
- Set `ast_node` and `irep_node` on query context before sending it to middleware #348
- Enum values can be extended with `.define` #341
### Bug Fixes
- Use `RelationConnection` for Rails 3 relations (which also extend `Array`) #343
- Fix schema printout when arguments have comments #335
## 0.19.4 (18 Oct 2016)
### Breaking changes
- `Relay::BaseConnection#order` was removed (it always returned `nil`) #313
- In the IDL, Interface names & Union members are parsed as `TypeName` nodes instead of Strings #322
### New features
- Print and parse descriptions in the IDL #305
- Schema roots from IDL are omitted when their names match convention #320
- Don't add `rescue_middleware` to a schema if it's not using `rescue_from` #328
- `Query::Arguments#each_value` yields `Query::Argument::ArgumentValue` instances which contain key, value and argument definition #331
### Bug fixes
- Use `JSON.generate(val, quirks_mode: true)` for compatibility with other JSON implementations #316
- Improvements for compatibility with 1.9.3 branch #315 #314 #313
- Raise a descriptive error when calculating a `cursor` for a node which isn't present in the connection's members #327
## 0.19.3 (13 Oct 2016)
### Breaking Changes
- `GraphQL::Query::Arguments.new` requires `argument_definitions:` of type `{String => GraphQL::Argument }` #304
### Deprecations
- `Relay::Mutation#resolve` has a new signature. #301
Previously, it was called with two arguments:
```ruby
resolve ->(inputs, ctx) { ... }
```
Now, it's called with three inputs:
```ruby
resolve ->(obj, inputs, ctx) { ... }
```
`obj` is the value of `root_value:` given to `Schema#execute`, as with other root-level fields.
Two-argument resolvers are still supported, but they are deprecated and will be removed in a future version.
### New features
- `Relay::Mutation` accepts a user-defined `return_type` #310
- `Relay::Mutation#resolve` receives the `root_value` passed to `Schema#execute` #301
- Derived `Relay` objects have descriptions #303
### Bug fixes
- Introspection query is 7 levels deep instead of 3 #308
- Unknown variable types cause validation errors, not runtime errors #310
- `Query::Arguments` doesn't wrap hashes from parsed scalars (fix for user-defined "JSONScalar") #304
## 0.19.2 (6 Oct 2016)
### New features
- If a list entry has a `GraphQL::ExecutionError`, replace the entry with `nil` and return the error #295
### Bug fixes
- Support graphql-batch rescuing `InvalidNullError`s #296
- Schema printer prints Enum names, not Ruby values for enums #297
## 0.19.1 (4 Oct 2016)
### Breaking changes
- Previously-deprecated `InterfaceType#resolve_type` hook has been removed, use `Schema#resolve_type` instead #290
### New features
- Eager-load schemas at definition time, validating types & schema-level hooks #289
- `InvalidNullError`s contain the type & field name that returned null #293
- If an object is resolved with `Schema#resolve_type` and the resulting type is not a member of the expected possible types, raise an error #291
### Bug fixes
- Allow `directive` as field or argument name #288
## 0.19.0 (30 Sep 2016)
### Breaking changes
- `GraphQL::Relay::GlobalNodeIdentification` was removed. Its features were moved to `GraphQL::Schema` or `GraphQL::Relay::Node`. The new hooks support more robust & flexible global IDs. #243
- Relay's `"Node"` interface and `node(id: "...")` field were both moved to `GraphQL::Relay::Node`. To use them in your schema, call `.field` and `.interface`. For example:
```ruby
# Adding a Relay-compliant `node` field:
field :node, GraphQL::Relay::Node.field
```
```ruby
# This object type implements Relay's `Node` interface:
interfaces [GraphQL::Relay::Node.interface]
```
- UUID hooks were renamed and moved to `GraphQL::Schema`. You should define `id_from_object` and `object_from_id` in your `Schema.define { ... }` block. For example:
```ruby
MySchema = GraphQL::Schema.define do
# Fetch an object by UUID
object_from_id ->(id, ctx) {
MyApp::RelayLookup.find(id)
}
# Generate a UUID for this object
id_from_object ->(obj, type_defn, ctx) {
MyApp::RelayLookup.to_id(obj)
}
end
```
- The new hooks have no default implementation. To use the previous default, use `GraphQL::Schema::UniqueWithinType`, for example:
```ruby
MySchema = GraphQL::Schema.define do
object_from_id ->(id, ctx) {
# Break the id into its parts:
type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id)
# Fetch the identified object
# ...
}
id_from_object ->(obj, type_defn, ctx) {
# Provide the type name & the object's `id`:
GraphQL::Schema::UniqueWithinType.encode(type_defn.name, obj.id)
}
end
```
If you were using a custom `id_separator`, it's now accepted as an input to `UniqueWithinType`'s methods, as `separator:`. For example:
```ruby
# use "---" as a ID separator
GraphQL::Schema::UniqueWithinType.encode(type_name, object_id, separator: "---")
GraphQL::Schema::UniqueWithinType.decode(relay_id, separator: "---")
```
- `type_from_object` was previously deprecated and has been replaced by `Schema#resolve_type`. You should define this hook in your schema to return a type definition for a given object:
```ruby
MySchema = GraphQL::Schema.define do
# ...
resolve_type ->(obj, ctx) {
# based on `obj` and `ctx`,
# figure out which GraphQL type to use
# and return the type
}
end
```
- `Schema#node_identification` has been removed.
- `Argument` default values have been changed to be consistent with `InputObjectType` default values. #267
Previously, arguments expected GraphQL values as `default_value`s. Now, they expect application values. (`InputObjectType`s always worked this way.)
Consider an enum like this one, where custom values are provided:
```ruby
PowerStateEnum = GraphQL::EnumType.define do
name "PowerState"
value("ON", value: 1)
value("OFF", value: 0)
end
```
__Previously__, enum _names_ were provided as default values, for example:
```ruby
field :setPowerState, PowerStateEnum do
# Previously, the string name went here:
argument :newValue, default_value: "ON"
end
```
__Now__, enum _values_ are provided as default values, for example:
```ruby
field :setPowerState, PowerStateEnum do
# Now, use the application value as `default_value`:
argument :newValue, default_value: 1
end
```
Note that if you __don't have custom values__, then there's no change, because the name and value are the same.
Here are types that are affected by this change:
- Custom scalars (previously, the `default_value` was a string, now it should be the application value, eg `Date` or `BigDecimal`)
- Enums with custom `value:`s (previously, the `default_value` was the name, now it's the value)
If you can't replace `default_value`s, you can also use a type's `#coerce_input` method to translate a GraphQL value into an application value. For example:
```ruby
# Using a custom scalar, "Date"
# PREVIOUSLY, provide a string:
argument :starts_on, DateType, default_value: "2016-01-01"
# NOW, transform the string into a Date:
argument :starts_on, DateType, default_value: DateType.coerce_input("2016-01-01")
```
### New features
- Support `@deprecated` in the Schema language #275
- Support `directive` definitions in the Schema language #280
- Use the same introspection field descriptions as `graphql-js` #284
### Bug fixes
- Operation name is no longer present in execution error `"path"` values #276
- Default values are correctly dumped & reloaded in the Schema language #267
## 0.18.15 (20 Sep 2016)
### Breaking changes
- Validation errors no longer have a `"path"` key in their JSON. It was renamed to `"fields"` #264
- `@skip` and `@include` over multiple selections are handled according to the spec: if the same field is selected multiple times and _one or more_ of them would be included, the field will be present in the response. Previously, if _one or more_ of them would be skipped, it was absent from the response. #256
### New features
- Execution errors include a `"path"` key which points to the field in the response where the error occurred. #259
- Parsing directives from the Schema language is now supported #273
### Bug fixes
- `@skip` and `@include` over multiple selections are now handled according to the spec #256
## 0.18.14 (20 Sep 2016)
### Breaking changes
- Directives are no longer considered as "conflicts" in query validation. This is in conformity with the spec, but a change for graphql-ruby #263
### Features
- Query analyzers may emit errors by raising `GraphQL::AnalysisError`s during `#call` or returning a single error or an array of errors from `#final_value` #262
### Bug fixes
- Merge fields even when `@skip` / `@include` are not identical #263
- Fix possible infinite loop in `FieldsWillMerge` validation #261
## 0.18.13 (19 Sep 2016)
### Bug fixes
- Find infinite loops in nested contexts, too #258
## 0.18.12 (19 Sep 2016)
### New features
- `GraphQL::Analysis::FieldUsage` can be used to check for deprecated fields in the query analysis phase #245
### Bug fixes
- If a schema receives a query on `mutation` or `subscription` but that root doesn't exist, return a validation error #254
- `Query::Arguments#to_h` only includes keys that were provided in the query or have a default value #251
## 0.18.11 (11 Sep 2016)
### New features
- `GraphQL::Language::Nodes::Document#slice(operation_name)` finds that operation and its dependencies and puts them in a new `Document` #241
### Bug fixes
- Validation errors for non-existent fields have the location of the field usage, not the parent field #247
- Properly `require "forwardable"` #242
- Remove `ALLOWED_CONSTANTS` for boolean input, use a plain comparison #240
## 0.18.10 (9 Sep 2016)
### New features
- Assign `#mutation` on objects which are derived from a `Relay::Mutation` #239
## 0.18.9 (6 Sep 2016)
### Bug fixes
- fix backward compatibility for `type_from_object` #238
## 0.18.8 (6 Sep 2016)
### New features
- AST nodes now respond to `#eql?(other)` to test value equality #231
### Bug fixes
- The `connection` helper no longer adds a duplicate field #235
## 0.18.7 (6 Sep 2016)
### New features
- Support parsing nameless fragments (but not executing them) #232
### Bug fixes
- Allow `__type(name: "Whatever")` to return null, as per the spec #233
- Include a Relay mutation's description with a mutation field #225
## 0.18.6 (29 Aug 2016)
### New features
- ` GraphQL::Schema::Loader.load(schema_json)` turns an introspection result into a `GraphQL::Schema` #207
- `.define` accepts plural definitions for: object fields, interface fields field arguments, enum values #222
## 0.18.5 (27 Aug 2016)
### Deprecations
- `Schema.new` is deprecated; use `Schema.define` instead.
Before:
```ruby
schema = GraphQL::Schema.new(
query: QueryType,
mutation: MutationType,
max_complexity: 100,
types: [ExtraType, OtherType]
)
schema.node_identification = MyGlobalID
schema.rescue_from(ActiveRecord::RecordNotFound) { |err| "..." }
```
After:
```ruby
schema = GraphQL::Schema.define do
query QueryType
mutation MutationType
max_complexity 100
node_identification MyGlobalID
rescue_from(ActiveRecord::RecordNotFound) { |err| "..." }
# Types was renamed to `orphan_types` to avoid conflict with the `types` helper
orphan_types [ExtraType, OtherType]
end
```
This unifies the disparate methods of configuring a schema and provides new, more flexible design space. It also adds `#metadata` to schemas for user-defined storage.
- `UnionType#resolve_type`, `InterfaceType#resolve_type`, and `GlobalNodeIdentification#type_from_object` are deprecated, unify them into `Schema#resolve_type` instead.
Before:
```ruby
GraphQL::Relay::GlobalNodeIdentification.define do
type_from_object ->(obj) { ... }
end
GraphQL::InterfaceType.define do
resolve_type ->(obj, ctx) { ... }
end
```
After:
```ruby
GraphQL::Schema.define do
resolve_type ->(obj, ctx) { ... }
end
```
This simplifies type inference and prevents unexpected behavior when different parts of the schema resolve types differently.
### New features
- Include expected type in Argument errors #221
- Define schemas with `Schema.define` #208
- Define a global object-to-type function with `Schema#resolve_type` #216
### Bug fixes
## 0.18.4 (25 Aug 2016)
### New features
- `InvalidNullError`s expose a proper `#message` #217
### Bug fixes
- Return an empty result for queries with no operations #219
## 0.18.3 (22 Aug 2016)
### Bug fixes
- `Connection.new(:field)` is optional, not required #215
- 0.18.2 introduced a more restrictive approach to resolving interfaces & unions; revert that approach #212
## 0.18.2 (17 Aug 2016)
### New features
- Connection objects expose the `GraphQL::Field` that created them via `Connection#field` #206
## 0.18.1 (7 Aug 2016)
### Deprecations
- Unify `Relay` naming around `nodes` as the items of a connection:
- `Relay::BaseConnection.connection_for_nodes` replaces `Relay::BaseConnection.connection_for_items`
- `Relay::BaseConnection#nodes` replaces `Relay::BaseConnection#object`
### New features
- Connection fields' `.resolve_proc` is an instance of `Relay::ConnectionResolve` #204
- Types, fields and arguments can store arbitrary values in their `metadata` hashes #203
## 0.18.0 (4 Aug 2016)
### Breaking changes
- `graphql-relay` has been merged with `graphql`, you should remove `graphql-relay` from your gemfile. #195
### Deprecations
### New features
- `GraphQL.parse` can turn schema definitions into a `GraphQL::Language::Nodes::Document`. The document can be stringified again with `Document#to_query_string` #191
- Validation errors include a `path` to the part of the query where the error was found #198
- `.define` also accepts keywords for each helper method, eg `GraphQL::ObjectType.define(name: "PostType", ...)`
### Bug fixes
- `global_id_field`s have default complexity of 1, not `nil`
- Relay `pageInfo` is correct for connections limited by `max_page_size`
- Rescue invalid variable errors & missing operation name errors during query analysis
## 0.17.2 (26 Jul 2016)
### Bug fixes
- Correctly spread fragments when nested inside other fragments #194
## 0.17.1 (26 Jul 2016)
### Bug fixes
- Fix `InternalRepresentation::Node#inspect`
## 0.17.0 (21 Jul 2016)
### Breaking changes
- `InternalRepresentation::Node` API changes:
- `#definition_name` returns the field name on field nodes (while `#name` may have an alias)
- `#definitions` returns `{type => field}` pairs for possible fields on this node
- `#definition` is gone, it is equivalent to `node.definitions.values.first`
- `#on_types` is gone, it is equivalent to `node.definitions.keys`
### New features
- Accept `hash_key:` field option
- Call `.define { }` block lazily, so `-> { }` is not needed for circular references #182
### Bug fixes
- Support `on` as an Enum value
- If the same field is requested on multiple types, choose the maximum complexity among them (not the first)
## 0.16.1 (20 Jul 2016)
### Bug fixes
- Fix merging fragments on Union types (see #190, broken from #180)
## 0.16.0 (14 Jul 2016)
### Breaking changes & deprecations
- I don't _know_ that this breaks anything, but `GraphQL::Query::SerialExecution` now iterates over a tree of `GraphQL::InternalRepresentation::Node`s instead of an AST (`GraphQL::Language::Nodes::Document`).
### New features
- Query context keys can be assigned with `Context#[]=` #178
- Cancel further field resolution with `TimeoutMiddleware` #179
- Add `GraphQL::InternalRepresentation` for normalizing queries from AST #180
- Analyze the query before running it #180
- Assign complexity cost to fields, enforce max complexity before running it #180
- Log max complexity or max depth with `MaxComplexity` or `MaxDepth` analyzers #180
- Query context exposes `#irep_node`, the internal representation of the current node #180
### Bug fixes
- Non-null errors are propagated to the next nullable field, all the way up to `data` #174
## 0.15.3 (28 Jun 2016)
### New features
- `EnumValue`s can receive their properties after instantiation #171
## 0.15.2 (16 Jun 2016)
### New features
- Support lazy type arguments in Object's `interfaces` and Union's `possible_types` #169
### Bug fixes
- Support single-member Unions, as per the spec #170
## 0.15.1 (15 Jun 2016)
### Bug fixes
- Whitelist operation types in `lexer.rb`
## 0.15.0 (11 Jun 2016)
### Breaking changes & deprecations
- Remove `debug:` option, propagate all errors. #161
## 0.14.1 (11 Jun 2016)
### Breaking changes & deprecations
- `debug:` is deprecated (#165). Propagating errors (`debug: true`) will become the default behavior. You can get a similar implementation of error gobbling with `CatchallMiddleware`. Add it to your schema:
```ruby
MySchema.middleware << GraphQL::Schema::CatchallMiddleware
```
### New features
### Bug fixes
- Restore previous introspection fields on DirectiveType as deprecated #164
- Apply coercion to input default values #162
- Proper Enum behavior when a value isn't found
## 0.14.0 (31 May 2016)
### Breaking changes & deprecations
### New features
- `GraphQL::Language::Nodes::Document#to_query_string` will re-serialize a query AST #151
- Accept `root_value:` when running a query #157
- Accept a `GraphQL::Language::Nodes::Document` to `Query.new` (this allows you to cache parsed queries on the server) #152
### Bug fixes
- Improved parse error messages #149
- Improved build-time validation #150
- Raise a meaningful error when a Union or Interface can't be resolved during query execution #155
## 0.13.0 (29 Apr 2016)
### Breaking changes & deprecations
- "Dangling" object types are not loaded into the schema. The must be passed in `GraphQL::Schema.new(types: [...])`. (This was deprecated in 0.12.1)
### New features
- Update directive introspection to new spec #121
- Improved schema validation errors #113
- 20x faster parsing #119
- Support inline fragments without type condition #123
- Support multiple schemas composed of the same types #142
- Accept argument `description` and `default_value` in the block #138
- Middlewares can send _new_ arguments to subsequent middlewares #129
### Bug fixes
- Don't leak details of internal errors #120
- Default query `context` to `{}` #133
- Fixed list nullability validation #131
- Ensure field names are strings #128
- Fix `@skip` and `@include` implementation #124
- Interface membership is not shared between schemas #142
## 0.12.1 (26 Apr 2016)
### Breaking changes & deprecations
- __Connecting object types to the schema _only_ via interfaces is deprecated.__ It will be unsupported in the next version of `graphql`.
Sometimes, object type is only connected to the Query (or Mutation) root by being a member of an interface. In these cases, bugs happen, especially with Rails development mode. (And sometimes, the bugs don't appear until you deploy to a production environment!)
So, in a case like this:
```ruby
HatInterface = GraphQL::ObjectType.define do
# ...
end
FezType = GraphQL::ObjectType.define do
# ...
interfaces [HatInterface]
end
QueryType = GraphQL::ObjectType.define do
field :randomHat, HatInterface # ...
end
```
`FezType` can only be discovered by `QueryType` _through_ `HatInterface`. If `fez_type.rb` hasn't been loaded by Rails, `HatInterface.possible_types` will be empty!
Now, `FezType` must be passed to the schema explicitly:
```ruby
Schema.new(
# ...
types: [FezType]
)
```
Since the type is passed directly to the schema, it will be loaded right away!
### New features
### Bug fixes
## 0.12.0 (20 Mar 2016)
### Breaking changes & deprecations
- `GraphQL::DefinitionConfig` was replaced by `GraphQL::Define` #116
- Many scalar types are more picky about which inputs they allow (#115). To get the previous behavior, add this to your program:
```ruby
# Previous coerce behavior for scalars:
GraphQL::BOOLEAN_TYPE.coerce = ->(value) { !!value }
GraphQL::ID_TYPE.coerce = ->(value) { value.to_s }
GraphQL::STRING_TYPE.coerce = ->(value) { value.to_s }
# INT_TYPE and FLOAT_TYPE were unchanged
```
- `GraphQL::Field`s can't be renamed because `#resolve` may depend on that name. (This was only a problem if you pass the _same_ `GraphQL::Field` instance to `field ... field:` definitions.)
- `GraphQL::Query::DEFAULT_RESOLVE` was removed. `GraphQL::Field#resolve` handles that behavior.
### New features
- Can override `max_depth:` from `Schema#execute`
- Base `GraphQL::Error` for all graphql-related errors
### Bug fixes
- Include `""` for String default values (so it's encoded as a GraphQL string literal)
## 0.11.1 (6 Mar 2016)
### New features
- Schema `max_depth:` option #110
- Improved validation errors for input objects #104
- Interfaces provide field implementations to object types #108
## 0.11.0 (28 Feb 2016)
### Breaking changes & deprecations
- `GraphQL::Query::BaseExecution` was removed, you should probably extend `SerialExecution` instead #96
- `GraphQL::Language::Nodes` members no longer raise if they don't get inputs during `initialize` #92
- `GraphQL.parse` no longer accepts `as:` for parsing partial queries. #92
### New features
- `Field#property` & `Field#property=` can be used to access & modify the method that will be sent to the underlying object when resolving a field #88
- When defining a field, you can pass a string for as `type`. It will be looked up in the global namespace.
- `Query::Arguments#to_h` unwraps `Arguments` objects recursively
- If you raise `GraphQL::ExecutionError` during field resolution, it will be rescued and the message will be added to the response's `errors` key. #93
- Raise an error when non-null fields are `nil` #94
### Bug fixes
- Accept Rails params as input objects
- Don't get a runtime error when input contains unknown key #100
## 0.10.9 (15 Jan 2016)
### Bug fixes
- Handle re-assignment of `ObjectType#interfaces` #84
- Fix merging queries on interface-typed fields #85
## 0.10.8 (14 Jan 2016)
### Bug fixes
- Fix transform of nested lists #79
- Fix parse & transform of escaped characters #83
## 0.10.7 (22 Dec 2015)
### New features
- Support Rubinius
### Bug fixes
- Coerce values into one-item lists for ListTypes
## 0.10.6 (20 Dec 2015)
### Bug fixes
- Remove leftover `puts`es
## 0.10.5 (19 Dec 2015)
### Bug fixes
- Accept enum value description in definition #71
- Correctly parse empty input objects #75
- Correctly parse arguments preceded by newline
- Find undefined input object keys during static validation
## 0.10.4 (24 Nov 2015)
### New features
- Add `Arguments#to_h` #66
### Bug fixes
- Accept argument description in definition
- Correctly parse empty lists
## 0.10.3 (11 Nov 2015)
### New features
- Support root-level `subscription` type
### Bug fixes
- Require Set for Schema::Printer
## 0.10.2 (10 Nov 2015)
### Bug fixes
- Handle blank strings in queries
- Raise if a field is configured without a proper type #61
## 0.10.1 (22 Oct 2015)
### Bug fixes
- Properly merge fields on fragments within fragments
- Properly delegate enumerable-ish methods on `Arguments` #56
- Fix & refactor literal coersion & validation #53
## 0.10.0 (17 Oct 2015)
### New features
- Scalars can have distinct `coerce_input` and `coerce_result` methods #48
- Operations don't require a name #54
### Bug fixes
- Big refactors and fixes to variables and arguments:
- Correctly apply argument default values
- Correctly apply variable default values
- Raise at execution-time if non-null variables are missing
- Incoming values are coerced to their proper types before execution
## 0.9.5 (1 Oct 2015)
### New features
- Add `Schema#middleware` to wrap field access
- Add `RescueMiddleware` to handle errors during field execution
- Add `Schema::Printer` for printing the schema definition #45
### Bug fixes
## 0.9.4 (22 Sept 2015)
### New features
- Fields can return `GraphQL::ExecutionError`s to add errors to the response
### Bug fixes
- Fix resolution of union types in some queries #41
## 0.9.3 (15 Sept 2015)
### New features
- Add `Schema#execute` shorthand for running queries
- Merge identical fields in fragments so they're only resolved once #34
- An error during parsing raises `GraphQL::ParseError` #33
### Bug fixes
- Find nested input types in `TypeReducer` #35
- Find variable usages inside fragments during static validation
## 0.9.2, 0.9.1 (10 Sept 2015)
### Bug fixes
- remove Celluloid dependency
## 0.9.0 (10 Sept 2015)
### Breaking changes & deprecations
- remove `GraphQL::Query::ParallelExecution` (use [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel))
## 0.8.1 (10 Sept 2015)
### Breaking changes & deprecations
- `GraphQL::Query::ParallelExecution` has been extracted to [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel)
## 0.8.0 (4 Sept 2015)
### New features
- Async field resolution with `context.async { ... }`
- Access AST node during resolve with `context.ast_node`
### Bug fixes
- Fix for validating arguments returning up too soon
- Raise if you try to define 2 types with the same name
- Raise if you try to get a type by name but it doesn't exist
## 0.7.1 (27 Aug 2015)
### Bug fixes
- Merge nested results from different fragments instead of using the latest one only
## 0.7.0 (26 Aug 2015)
### Breaking changes & deprecations
- Query keyword argument `params:` was removed, use `variables:` instead.
### Bug fixes
- `@skip` has precedence over `@include`
- Handle when `DEFAULT_RESOVE` returns nil
## 0.6.2 (20 Aug 2015)
### Bug fixes
- Fix whitespace parsing in input objects
## 0.6.1 (16 Aug 2015)
### New features
- Parse UTF-8 characters & escaped characters
### Bug fixes
- Properly parse empty strings
- Fix argument / variable compatibility validation
## 0.6.0 (14 Aug 2015)
### Breaking changes & deprecations
- Deprecate `params` option to `Query#new` in favor of `variables`
- Deprecated `.new { |obj, types, fields, args| }` API was removed (use `.define`)
### New features
- `Query#new` accepts `operation_name` argument
- `InterfaceType` and `UnionType` accept `resolve_type` configs
### Bug fixes
- Gracefully handle blank-string & whitespace-only queries
- Handle lists in variable definitions and arguments
- Handle non-null input types
## 0.5.0 (12 Aug 2015)
### Breaking changes & deprecations
- Deprecate definition API that yielded a bunch of helpers #18
### New features
- Add new definition API #18
graphql-ruby-1.11.10/CNAME 0000664 0000000 0000000 00000000021 14141214530 0015022 0 ustar 00root root 0000000 0000000 graphql-ruby.org
graphql-ruby-1.11.10/Gemfile 0000664 0000000 0000000 00000000733 14141214530 0015561 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
source "https://rubygems.org"
gemspec
gem 'bootsnap' # required by the Rails apps generated in tests
gem 'ruby-prof', platform: :ruby
gem 'pry'
gem 'pry-stack_explorer', platform: :ruby
if RUBY_VERSION >= "2.4"
gem 'pry-byebug'
end
# Required for running `jekyll algolia ...` (via `rake site:update_search_index`)
group :jekyll_plugins do
if RUBY_VERSION >= "2.3"
gem 'jekyll-algolia', '~> 1.0'
end
gem 'jekyll-redirect-from'
end
graphql-ruby-1.11.10/Guardfile 0000664 0000000 0000000 00000002501 14141214530 0016106 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
guard :minitest, test_file_patterns: ["*_spec.rb"] do
# with Minitest::Spec
watch(%r{^spec/(.*)_spec\.rb})
watch(%r{^lib/(.+)\.rb}) { |m|
# When a project file changes, run any of:
# - Corresponding `spec/` file
# - Corresponding `spec/` file
# for the file named in `test_via:`
to_run = []
matching_spec = "spec/#{m[1]}_spec.rb"
if File.exist?(matching_spec)
to_run << matching_spec
end
# If the file was deleted, it won't exist anymore
if File.exist?(m[0])
# Find a `# test_via:` macro to automatically run another test
body = File.read(m[0])
test_via_match = body.match(/test_via: (.*)/)
if test_via_match
test_via_path = test_via_match[1]
companion_file = Pathname.new(m[0] + "/../" + test_via_path)
.cleanpath
.to_s
.sub(/.rb/, "_spec.rb")
.sub("lib/", "spec/")
to_run << companion_file
end
end
# 0+ files
to_run
}
watch(%r{^spec/spec_helper\.rb}) { "spec" }
watch(%r{^spec/support/.*\.rb}) { "spec" }
end
guard "rake", task: "build_parser" do
watch("lib/graphql/language/parser.y")
watch("lib/graphql/language/lexer.rl")
end
guard :rubocop, all_on_start: false do
watch(%r{^spec/.*.\rb})
watch(%r{^lib/.*\.rb})
end
graphql-ruby-1.11.10/MIT-LICENSE 0000664 0000000 0000000 00000002036 14141214530 0015720 0 ustar 00root root 0000000 0000000 Copyright 2015 Robert Mosolgo
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
graphql-ruby-1.11.10/Rakefile 0000664 0000000 0000000 00000006433 14141214530 0015736 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "bundler/setup"
Bundler.require
Bundler::GemHelper.install_tasks
require "rake/testtask"
require_relative "guides/_tasks/site"
require_relative "lib/graphql/rake_task/validate"
Rake::TestTask.new do |t|
t.libs << "spec" << "lib"
exclude_integrations = []
['Mongoid', 'Rails'].each do |integration|
begin
Object.const_get(integration)
rescue NameError
exclude_integrations << integration.downcase
end
end
t.test_files = Dir['spec/**/*_spec.rb'].reject do |f|
next unless f.start_with?("spec/integration/")
excluded = exclude_integrations.any? do |integration|
f.start_with?("spec/integration/#{integration}/")
end
puts "+ #{f}" unless excluded
excluded
end
t.warning = false
end
require 'rubocop/rake_task'
RuboCop::RakeTask.new
default_tasks = [:test, :rubocop]
if ENV["SYSTEM_TESTS"]
task(default: ["test:system"] + default_tasks)
else
task(default: default_tasks)
end
desc "Use Racc & Ragel to regenerate parser.rb & lexer.rb from configuration files"
task :build_parser do
def assert_dependency_version(dep_name, required_version, check_script)
version = `#{check_script}`
if !version.include?(required_version)
raise <<-ERR
build_parser requires #{dep_name} version "#{required_version}", but found:
$ #{check_script}
> #{version}
To fix this issue:
- Update #{dep_name} to the required version
- Update the assertion in `Rakefile` to match the current version
ERR
end
end
assert_dependency_version("Ragel", "7.0.0.9", "ragel -v")
assert_dependency_version("Racc", "1.4.16", %|ruby -e "require 'racc'; puts Racc::VERSION"|)
`rm -f lib/graphql/language/parser.rb lib/graphql/language/lexer.rb `
`racc lib/graphql/language/parser.y -o lib/graphql/language/parser.rb`
`ragel -R -F1 lib/graphql/language/lexer.rl`
end
namespace :bench do
def prepare_benchmark
$LOAD_PATH << "./lib" << "./spec/support"
require_relative("./benchmark/run.rb")
end
desc "Benchmark the introspection query"
task :query do
prepare_benchmark
GraphQLBenchmark.run("query")
end
desc "Benchmark validation of several queries"
task :validate do
prepare_benchmark
GraphQLBenchmark.run("validate")
end
desc "Generate a profile of the introspection query"
task :profile do
prepare_benchmark
GraphQLBenchmark.profile
end
desc "Run benchmarks on a very large result"
task :profile_large_result do
prepare_benchmark
GraphQLBenchmark.profile_large_result
end
end
namespace :test do
desc "Run system tests for ActionCable subscriptions"
task :system do
success = Dir.chdir("spec/dummy") do
system("bundle install")
system("bundle exec bin/rails test:system")
end
success || abort
end
task js: "js:test"
end
namespace :js do
client_dir = "./javascript_client"
desc "Run the tests for javascript_client"
task :test do
success = Dir.chdir(client_dir) do
system("yarn run test")
end
success || abort
end
desc "Install JS dependencies"
task :install do
Dir.chdir(client_dir) do
system("yarn install")
end
end
desc "Compile TypeScript to JavaScript"
task :build do
Dir.chdir(client_dir) do
system("yarn tsc")
end
end
task all: [:install, :build, :test]
end
graphql-ruby-1.11.10/benchmark/ 0000775 0000000 0000000 00000000000 14141214530 0016215 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/benchmark/abstract_fragments.graphql 0000664 0000000 0000000 00000000674 14141214530 0023455 0 ustar 00root root 0000000 0000000 query AbstractFragments {
node(id: "1") {
...Frag1
}
}
fragment Frag1 on Commentable {
id
__typename
...Frag2
}
fragment Frag2 on Commentable {
id
__typename
...Frag3
}
fragment Frag3 on Commentable {
id
__typename
...Frag4
}
fragment Frag4 on Commentable {
id
__typename
...Frag5
}
fragment Frag5 on Commentable {
id
__typename
...Frag6
}
fragment Frag6 on Commentable {
comments {
body
}
}
graphql-ruby-1.11.10/benchmark/abstract_fragments_2.graphql 0000664 0000000 0000000 00000001230 14141214530 0023663 0 ustar 00root root 0000000 0000000 query AbstractFragments {
node(id: "1") {
...Frag1
}
}
fragment Frag1 on Commentable {
id
__typename
...Frag9
...Frag2
}
fragment Frag2 on Commentable {
id
__typename
...Frag9
...Frag3
}
fragment Frag3 on Commentable {
id
__typename
...Frag9
...Frag4
}
fragment Frag4 on Commentable {
id
__typename
...Frag9
...Frag5
}
fragment Frag5 on Commentable {
id
__typename
...Frag9
...Frag6
}
fragment Frag6 on Commentable {
...Frag7
...Frag9
name
id
comments {
...Frag8
...Frag7
id
}
}
fragment Frag7 on Node {
id
}
fragment Frag8 on Comment {
body
}
fragment Frag9 on Named {
name
}
graphql-ruby-1.11.10/benchmark/big_query.graphql 0000664 0000000 0000000 00000015561 14141214530 0021573 0 ustar 00root root 0000000 0000000 query Anc_inbox_layout($first_0:Int!,$first_5:Int!,$first_6:Int!,$first_a:Int!,$first_c:Int!,$order_by_1:ReportOrderInput!,$substate_2:ReportStateEnum!,$pre_submission_review_states_3:[ReportPreSubmissionReviewStateEnum]!,$size_4:ProfilePictureSizes!,$size_9:ProfilePictureSizes!,$not_types_7:[ActivityTypes]!,$order_by_8:ActivityOrderInput!,$order_by_b:TeamOrderInput!) {
query {
id,
...FE
}
}
fragment F0 on User {
username,
_profile_picturePkPpF:profile_picture(size:$size_4),
impact,
reputation,
signal,
id
}
fragment F1 on Report {
reporter {
username,
_profile_picturePkPpF:profile_picture(size:$size_4),
impact,
reputation,
signal,
_duplicate_users2Nhzxe:duplicate_users(first:$first_5) {
pageInfo {
hasNextPage,
hasPreviousPage
},
total_count,
edges {
node {
id,
...F0
},
cursor
}
},
id
},
id
}
fragment F2 on Report {
id
}
fragment F3 on Node {
id,
__typename
}
fragment F4 on ReportActivityInterface {
automated_response,
genius_execution_id,
report {
team {
handle,
id
},
id
},
__typename,
...F3
}
fragment F5 on Team {
url,
internet_bug_bounty,
_profile_pictureihzmG:profile_picture(size:$size_9),
name,
id
}
fragment F6 on User {
username,
url,
_profile_pictureihzmG:profile_picture(size:$size_9),
id
}
fragment F7 on ActivitiesBugDuplicate {
original_report_id,
id
}
fragment F8 on ActivitiesReferenceIdAdded {
reference,
reference_url,
id
}
fragment F9 on ActivitiesCveIdAdded {
cve_ids,
id
}
fragment Fa on ActivitiesAgreedOnGoingPublic {
first_to_agree,
id
}
fragment Fb on ActivitiesBugCloned {
original_report_id,
id
}
fragment Fc on ActivitiesUserAssignedToBug {
assigned_user {
url,
username,
id
},
id
}
fragment Fd on ActivitiesGroupAssignedToBug {
assigned_group {
name,
id
},
id
}
fragment Fe on ActivitiesExternalUserInvited {
email,
id
}
fragment Ff on ActivitiesExternalUserInvitationCancelled {
email,
id
}
fragment Fg on ActivitiesExternalUserRemoved {
removed_user {
id
},
id
}
fragment Fh on ActivitiesUserBannedFromProgram {
removed_user {
id
},
id
}
fragment Fi on ActivitiesBountyAwarded {
bounty_amount,
bounty_currency,
bonus_amount,
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fj on ActivitiesBountySuggested {
bounty_amount,
bounty_currency,
bonus_amount,
id
}
fragment Fk on ActivitiesBugResolved {
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fl on ActivitiesSwagAwarded {
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fm on ActivitiesChangedScope {
old_scope {
asset_identifier,
id
},
new_scope {
asset_identifier,
id
},
id
}
fragment Fn on ActivityInterface {
_id,
internal,
i_can_edit,
__typename,
message,
markdown_message,
created_at,
updated_at,
actor {
__typename,
...F5,
...F6,
...F3
},
attachments {
_id,
file_name,
content_type,
expiring_url,
id
},
...F7,
...F8,
...F9,
...Fa,
...Fb,
...Fc,
...Fd,
...Fe,
...Ff,
...Fg,
...Fh,
...Fi,
...Fj,
...Fk,
...Fl,
...Fm,
...F3
}
fragment Fo on User {
username,
url,
__typename,
id
}
fragment Fp on TeamMemberGroup {
name,
__typename,
id
}
fragment Fq on Report {
_id,
url,
title,
state,
substate,
created_at,
assignee {
__typename,
...Fo,
...Fp,
...F3
},
cloned_from {
_id,
id
},
reporter {
username,
url,
id
},
team {
_id,
url,
handle,
name,
twitter_handle,
website,
about,
offers_bounties,
id
},
id
}
fragment Fr on Report {
state,
stage,
disclosed_at,
cve_ids,
singular_disclosure_disabled,
disclosed_at,
bug_reporter_agreed_on_going_public_at,
team_member_agreed_on_going_public_at,
comments_closed,
mediation_requested_at,
vulnerability_information,
vulnerability_information_html,
reporter {
disabled,
username,
url,
_profile_picture2g6hJa:profile_picture(size:$size_4),
id
},
weakness {
id,
name
},
original_report {
id,
url
},
attachments {
_id,
file_name,
expiring_url,
content_type,
id
},
allow_singular_disclosure_at,
allow_singular_disclosure_after,
singular_disclosure_allowed,
severity {
rating,
score,
author_type,
id
},
structured_scope {
_id,
asset_type,
asset_identifier,
max_severity,
id
},
_activities4z6spP:activities(first:$first_6,not_types:$not_types_7,order_by:$order_by_8) {
edges {
node {
__typename,
...F4,
...Fn,
...F3
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...Fq
}
fragment Fs on Report {
id,
...Fr
}
fragment Ft on Report {
title,
id
}
fragment Fu on Report {
_id,
pre_submission_review_state,
i_can_anc_review,
reporter {
username,
id
},
team {
handle,
id
},
id,
...F2
}
fragment Fv on Report {
team {
policy_html,
id
},
structured_scope {
asset_identifier,
asset_type,
instruction,
id
},
id
}
fragment Fw on Report {
weakness {
name,
id
},
id
}
fragment Fx on Report {
severity {
rating,
score,
id
},
id
}
fragment Fy on Report {
latest_activity_at,
created_at,
id,
...Fq
}
fragment Fz on Query {
me {
username,
_teamsWbVmT:teams(order_by:$order_by_b,first:$first_c) {
edges {
node {
name,
handle,
id
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id
},
id
}
fragment FA on Query {
_reports1t04lE:reports(page:$first_0,first:$first_a,limit:$first_a,order_by:$order_by_1,substate:$substate_2,pre_submission_review_states:$pre_submission_review_states_3) {
total_count,
edges {
node {
_id,
id,
...Fy
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...Fz
}
fragment FB on Query {
id,
...Fz
}
fragment FC on Query {
id
}
fragment FD on Query {
me {
username,
_profile_pictureihzmG:profile_picture(size:$size_9),
id
},
id,
...FC
}
fragment FE on Query {
_reports3QQXft:reports(first:$first_0,order_by:$order_by_1,substate:$substate_2,pre_submission_review_states:$pre_submission_review_states_3) {
edges {
node {
id,
...F1,
...F2,
...Fs,
...Ft,
...Fu,
...Fv,
...Fw,
...Fx
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...FA,
...FB,
...FD
}
graphql-ruby-1.11.10/benchmark/big_schema.graphql 0000664 0000000 0000000 00000337223 14141214530 0021670 0 ustar 00root root 0000000 0000000 # Autogenerated input type of AcceptInvitation
input AcceptInvitationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of AcceptInvitation
type AcceptInvitationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# Autogenerated input type of AcknowledgeProgramHealthAcknowledgementMutation
input AcknowledgeProgramHealthAcknowledgementMutationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
program_health_acknowledgement_id: ID!
}
# Autogenerated return type of AcknowledgeProgramHealthAcknowledgementMutation
type AcknowledgeProgramHealthAcknowledgementMutationPayload {
acknowledged_program_health_acknowledgement_id: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# A Activities::AgreedOnGoingPublic activity for a report
type ActivitiesAgreedOnGoingPublic implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
first_to_agree: Boolean!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BountyAwarded activity for a report
type ActivitiesBountyAwarded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
bonus_amount: String
bounty_amount: String
bounty_currency: String
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BountySuggested activity for a report
type ActivitiesBountySuggested implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
bonus_amount: String
bounty_amount: String
bounty_currency: String
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugCloned activity for a report
type ActivitiesBugCloned implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
original_report: Report
original_report_id: Int @deprecated(reason: "Deprecated in favor of .original_report")
report: Report
updated_at: String!
}
# A Activities::BugDuplicate activity for a report
type ActivitiesBugDuplicate implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
original_report: Report
original_report_id: Int @deprecated(reason: "Deprecated in favor of .original_report")
report: Report
updated_at: String!
}
# A Activities::BugFiled activity for a report
type ActivitiesBugFiled implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugInformative activity for a report
type ActivitiesBugInformative implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNeedsMoreInfo activity for a report
type ActivitiesBugNeedsMoreInfo implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNew activity for a report
type ActivitiesBugNew implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNotApplicable activity for a report
type ActivitiesBugNotApplicable implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugReopened activity for a report
type ActivitiesBugReopened implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugResolved activity for a report
type ActivitiesBugResolved implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugSpam activity for a report
type ActivitiesBugSpam implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugTriaged activity for a report
type ActivitiesBugTriaged implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ChangedScope activity for a report
type ActivitiesChangedScope implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_scope: StructuredScope
old_scope: StructuredScope
report: Report
updated_at: String!
}
# A Activities::Comment activity for a report
type ActivitiesComment implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::CommentsClosed activity for a report
type ActivitiesCommentsClosed implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::CveIdAdded activity for a report
type ActivitiesCveIdAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
cve_ids: [String]
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalAdvisoryAdded activity for a report
type ActivitiesExternalAdvisoryAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserInvitationCancelled activity for a report
type ActivitiesExternalUserInvitationCancelled implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
email: String
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserInvited activity for a report
type ActivitiesExternalUserInvited implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
email: String
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserJoined activity for a report
type ActivitiesExternalUserJoined implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
duplicate_report: Report
duplicate_report_id: Int @deprecated(reason: "Deprecated in favor of .duplicate_report")
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserRemoved activity for a report
type ActivitiesExternalUserRemoved implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
removed_user: User!
report: Report
updated_at: String!
}
# A Activities::GroupAssignedToBug activity for a report
type ActivitiesGroupAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
assigned_group: TeamMemberGroup
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
group: TeamMemberGroup @deprecated(reason: "deprecated in favor of assigned group")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::HackerRequestedMediation activity for a report
type ActivitiesHackerRequestedMediation implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ManuallyDisclosed activity for a report
type ActivitiesManuallyDisclosed implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::MediationRequested activity for a report
type ActivitiesMediationRequested implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# An Activities::NobodyAssignedToBug activity for a report
type ActivitiesNobodyAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::NotEligibleForBounty activity for a report
type ActivitiesNotEligibleForBounty implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReassignedToTeam activity for a report
type ActivitiesReassignedToTeam implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReferenceIdAdded activity for a report
type ActivitiesReferenceIdAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
reference: String
reference_url: String
report: Report
updated_at: String!
}
# A Activities::ReportBecamePublic activity for a report
type ActivitiesReportBecamePublic implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportCollaboratorInvited activity for a report
type ActivitiesReportCollaboratorInvited implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportCollaboratorJoined activity for a report
type ActivitiesReportCollaboratorJoined implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportSeverityUpdated activity for a report
type ActivitiesReportSeverityUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportTitleUpdated activity for a report
type ActivitiesReportTitleUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_title: String!
old_title: String!
report: Report
updated_at: String!
}
# A Activities::ReportVulnerabilityTypesUpdated activity for a report
type ActivitiesReportVulnerabilityTypesUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_weakness: Weakness
old_weakness: Weakness
report: Report
updated_at: String!
}
# A Activities::SwagAwarded activity for a report
type ActivitiesSwagAwarded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
swag: Swag!
updated_at: String!
}
# A Activities::TeamPublished activity for a team
type ActivitiesTeamPublished implements ActivityInterface, Node {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# A Activities::UserAssignedToBug activity for a report
type ActivitiesUserAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
assigned_user: User!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::UserBannedFromProgram activity for a report
type ActivitiesUserBannedFromProgram implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
removed_user: User!
report: Report
updated_at: String!
}
# A Activities::UserJoined activity for a user
type ActivitiesUserJoined implements ActivityInterface, Node {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# The connection type for ActivityUnion.
type ActivityConnection {
# A list of edges.
edges: [ActivityUnionEdge]
max_updated_at: String
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# A interface for the common fields on an HackerOne Activity
interface ActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# Fields on which a collection of activities can be ordered
enum ActivityOrderField {
created_at
updated_at
}
input ActivityOrderInput {
direction: OrderDirection!
field: ActivityOrderField!
}
# Possible types for an activity
enum ActivityTypes {
AgreedOnGoingPublic
BountyAwarded
BountySuggested
BugCloned
BugDuplicate
BugFiled
BugInformative
BugNeedsMoreInfo
BugNew
BugNotApplicable
BugReopened
BugResolved
BugSpam
BugTriaged
ChangedScope
Comment
CommentsClosed
CveIdAdded
ExternalAdvisoryAdded
ExternalUserInvitationCancelled
ExternalUserInvited
ExternalUserJoined
ExternalUserRemoved
GroupAssignedToBug
HackerRequestedMediation
ManuallyDisclosed
MediationRequested
NobodyAssignedToBug
NotEligibleForBounty
ReassignedToTeam
ReferenceIdAdded
ReportBecamePublic
ReportCollaboratorInvited
ReportCollaboratorJoined
ReportSeverityUpdated
ReportTitleUpdated
ReportVulnerabilityTypesUpdated
SwagAwarded
TeamPublished
UserAssignedToBug
UserBannedFromProgram
UserJoined
}
# Activities can be of multiple types
union ActivityUnion = ActivitiesAgreedOnGoingPublic | ActivitiesBountyAwarded | ActivitiesBountySuggested | ActivitiesBugCloned | ActivitiesBugDuplicate | ActivitiesBugFiled | ActivitiesBugInformative | ActivitiesBugNeedsMoreInfo | ActivitiesBugNew | ActivitiesBugNotApplicable | ActivitiesBugReopened | ActivitiesBugResolved | ActivitiesBugSpam | ActivitiesBugTriaged | ActivitiesChangedScope | ActivitiesComment | ActivitiesCommentsClosed | ActivitiesCveIdAdded | ActivitiesExternalAdvisoryAdded | ActivitiesExternalUserInvitationCancelled | ActivitiesExternalUserInvited | ActivitiesExternalUserJoined | ActivitiesExternalUserRemoved | ActivitiesGroupAssignedToBug | ActivitiesHackerRequestedMediation | ActivitiesManuallyDisclosed | ActivitiesMediationRequested | ActivitiesNobodyAssignedToBug | ActivitiesNotEligibleForBounty | ActivitiesReassignedToTeam | ActivitiesReferenceIdAdded | ActivitiesReportBecamePublic | ActivitiesReportCollaboratorInvited | ActivitiesReportCollaboratorJoined | ActivitiesReportSeverityUpdated | ActivitiesReportTitleUpdated | ActivitiesReportVulnerabilityTypesUpdated | ActivitiesSwagAwarded | ActivitiesTeamPublished | ActivitiesUserAssignedToBug | ActivitiesUserBannedFromProgram | ActivitiesUserJoined
# The connection type for ActivityUnion.
type ActivityUnionConnection {
# A list of edges.
edges: [ActivityUnionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type ActivityUnionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: ActivityUnion
}
# The actor of an activity can be multiple types
union ActorUnion = Team | User
# A HackerOne user's address used for submitting swag
type Address implements Node {
_id: ID!
city: String!
country: String!
created_at: String!
id: ID!
name: String!
phone_number: String
postal_code: String!
state: String!
street: String!
tshirt_size: TshirtSizeEnum @deprecated(reason: "Query tshirt size on User instead")
}
# Autogenerated input type of ArchiveStructuredScope
input ArchiveStructuredScopeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
structured_scope_id: ID!
}
# Autogenerated return type of ArchiveStructuredScope
type ArchiveStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
query: Query
structured_scope: StructuredScope
}
# Report can be assigned to either a user or a team member group
union AssigneeUnion = TeamMemberGroup | User
# A HackerOne attachment for a report
type Attachment implements Node {
_id: ID!
content_type: String!
created_at: String!
expiring_url: String!
file_name: String!
file_size: Int!
id: ID!
}
# Types of authentication methods for users
enum AuthenticationServiceEnum {
database
saml
token
}
# A HackerOne badge
type Badge implements Node {
_id: ID!
description: String!
id: ID!
image_path: String!
name: String!
}
# Represents a badge earned by a user
type BadgesUsers implements Node {
_id: ID!
badge: Badge!
created_at: String!
id: ID!
user: User!
}
# The connection type for BadgesUsers.
type BadgesUsersConnection {
# A list of edges.
edges: [BadgesUsersEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BadgesUsersEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BadgesUsers
}
# Resources for setting up the Bank Transfer payment method
type BankTransferReference implements Node {
beneficiary_required_details(currency: String!, bank_account_country: String!, beneficiary_country: String!): BeneficiaryRequiredDetail
countries: [Country]
currencies: [Currency]
id: ID!
}
# A specification of information needed to create a bank transfer payment preference
type BeneficiaryRequiredDetail implements Node {
bank_account_country: String!
beneficiary_country: String!
beneficiary_required_details(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BeneficiaryRequiredDetailsConnection
currency: String!
id: ID!
}
input BeneficiaryRequiredDetailInput {
field: String!
value: String!
}
# A specification of the possibilities for creating a bank transfer payout preference
type BeneficiaryRequiredDetails implements Node {
beneficiary_entity_type: String!
beneficiary_required_fields(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BeneficiaryRequiredFieldConnection
description: String!
fee: String!
id: ID!
payment_type: String!
}
# The connection type for BeneficiaryRequiredDetails.
type BeneficiaryRequiredDetailsConnection {
# A list of edges.
edges: [BeneficiaryRequiredDetailsEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BeneficiaryRequiredDetailsEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BeneficiaryRequiredDetails
}
# A specification of the format of a field used to create a bank transfer payout preference
type BeneficiaryRequiredField implements Node {
description: String!
field: String!
id: ID!
regex: String!
}
# The connection type for BeneficiaryRequiredField.
type BeneficiaryRequiredFieldConnection {
# A list of edges.
edges: [BeneficiaryRequiredFieldEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BeneficiaryRequiredFieldEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BeneficiaryRequiredField
}
# A HackerOne bounty for a report
type Bounty implements Node {
_id: ID!
amount: String!
awarded_amount: String!
awarded_bonus_amount: String!
awarded_currency: String!
bonus_amount: String!
created_at: String!
id: ID!
report: Report!
status: BountyStatusEnum!
}
# The connection type for Bounty.
type BountyConnection {
# A list of edges.
edges: [BountyEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_amount: Float!
total_count: Int!
}
# An edge in a connection.
type BountyEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Bounty
}
# Status which reflect the state of a bounty
enum BountyStatusEnum {
cancelled
confirmed
failed
failed_ofac_check
needs_payout_method
needs_tax_form
no_mileage_account
no_status
no_tax_form
ofac_reject
pending
pending_ofac_check
rejected
sent
}
# A subset of weaknesses that share a common characteristic
type Cluster implements Node {
created_at: String!
description: String
id: ID!
name: String!
updated_at: String!
weaknesses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: WeaknessOrder = {direction: ASC, field: name}
search: String = null
team_handle: String = null
team_weakness_state: [TeamWeaknessStates] = [enabled, disabled, hidden]
): ClusterWeaknessConnection
}
# The connection type for Cluster.
type ClusterConnection {
# A list of edges.
edges: [ClusterEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ClusterEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Cluster
}
input ClusterOrder {
direction: OrderDirection!
field: ClusterOrderField!
}
# Fields on which a collection of Cluster can be ordered
enum ClusterOrderField {
BROWSING_FRIENDLY
}
# The connection type for Weakness.
type ClusterWeaknessConnection {
# A list of edges.
edges: [ClusterWeaknessEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ClusterWeaknessEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Weakness
team_weakness(team_handle: String!): TeamWeakness
}
# A Coinbase Payout Preference
type CoinbasePayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# A common response
type CommonResponse implements Node {
# The primary key from the database
_id: ID!
created_at: String!
id: ID!
message: String!
team: Team!
title: String!
updated_at: String!
}
# The connection type for CommonResponse.
type CommonResponseConnection {
# A list of edges.
edges: [CommonResponseEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type CommonResponseEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: CommonResponse
}
input CommonResponseOrder {
direction: OrderDirection!
field: CommonResponseOrderField!
}
# Fields on which a collection of common responses can be ordered
enum CommonResponseOrderField {
title
}
# Will only return values for valid SeverityRatingEnum and null.
scalar CountBySeverity
# A country as specified in ISO 3166
type Country implements Node {
alpha2: String!
currency_code: String
id: ID!
name: String!
}
# Autogenerated input type of CreateActivityComment
input CreateActivityCommentInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
internal: Boolean!
message: String!
report_id: ID!
}
# Autogenerated return type of CreateActivityComment
type CreateActivityCommentPayload {
activities: ActivityUnionConnection
activity: ActivitiesComment
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
new_activity_edge: ActivityUnionEdge
report: Report
}
# Autogenerated input type of CreateBounty
input CreateBountyInput {
amount: Float
bonus_amount: Float
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateBounty
type CreateBountyPayload {
bounty: Bounty!
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated input type of CreateBountySuggestion
input CreateBountySuggestionInput {
amount: Float
bonus_amount: Float
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateBountySuggestion
type CreateBountySuggestionPayload {
activity: ActivitiesBountySuggested!
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated input type of CreateCoinbasePayoutPreference
input CreateCoinbasePayoutPreferenceInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
coinbase_email: String!
default_method: Boolean!
}
# Autogenerated return type of CreateCoinbasePayoutPreference
type CreateCoinbasePayoutPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# Autogenerated input type of CreateCurrencycloudBankTransferPayoutPreference
input CreateCurrencycloudBankTransferPayoutPreferenceInput {
bank_account_country: String!
bank_account_holder_name: String!
beneficiary_entity_type: CurrencycloudBankTransferEntityType!
beneficiary_required_details: [BeneficiaryRequiredDetailInput]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
currency: String!
default_method: Boolean!
payment_type: CurrencycloudBankTransferPaymentType!
}
# Autogenerated return type of CreateCurrencycloudBankTransferPayoutPreference
type CreateCurrencycloudBankTransferPayoutPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of CreateJiraOauthUrl
input CreateJiraOauthUrlInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
site: String!
team_id: ID!
}
# Autogenerated return type of CreateJiraOauthUrl
type CreateJiraOauthUrlPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
url: String
}
# Autogenerated input type of CreateJiraWebhookToken
input CreateJiraWebhookTokenInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of CreateJiraWebhookToken
type CreateJiraWebhookTokenPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team!
webhook_url: String!
}
# Autogenerated input type of CreateMailingAddress
input CreateMailingAddressInput {
city: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
country: String!
name: String!
phone_number: String!
postal_code: String!
state: String!
street: String!
}
# Autogenerated return type of CreateMailingAddress
type CreateMailingAddressPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateOrUpdateHackeroneToJiraEventsConfiguration
input CreateOrUpdateHackeroneToJiraEventsConfigurationInput {
assignee_changes: Boolean
# A unique identifier for the client performing the mutation.
clientMutationId: String
comments: Boolean
public_disclosures: Boolean
rewards: Boolean
state_changes: Boolean
team_id: ID!
}
# Autogenerated return type of CreateOrUpdateHackeroneToJiraEventsConfiguration
type CreateOrUpdateHackeroneToJiraEventsConfigurationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team!
}
# Autogenerated input type of CreateOrUpdateJiraIntegration
input CreateOrUpdateJiraIntegrationInput {
assignee: String
base_url: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
custom: String
description: String!
generate_webhook_in_jira_if_does_not_exist: Boolean
issue_type: Int!
labels: String
pid: Int!
summary: String!
team_id: ID!
}
# Autogenerated return type of CreateOrUpdateJiraIntegration
type CreateOrUpdateJiraIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of CreatePaypalPreference
input CreatePaypalPreferenceInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
default_method: Boolean!
paypal_email: String!
}
# Autogenerated return type of CreatePaypalPreference
type CreatePaypalPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateSlackPipeline
input CreateSlackPipelineInput {
channel: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
descriptive_label: String
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
team_id: ID!
}
# Autogenerated return type of CreateSlackPipeline
type CreateSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
new_slack_pipeline_edge: SlackPipelineEdge
slack_pipelines_connection: SlackPipelineConnection
team: Team!
}
# Autogenerated input type of CreateStructuredScope
input CreateStructuredScopeInput {
asset_identifier: String!
asset_type: StructuredScopedAssetTypeEnum
availability_requirement: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
confidentiality_requirement: String
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
instruction: String
integrity_requirement: String
reference: String
team_id: ID!
}
# Autogenerated return type of CreateStructuredScope
type CreateStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of CreateSurveyAnswer
input CreateSurveyAnswerInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
feedback: String
invitation_token: String
structured_response_ids: [ID]!
}
# Autogenerated return type of CreateSurveyAnswer
type CreateSurveyAnswerPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateSwag
input CreateSwagInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateSwag
type CreateSwagPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
swag: Swag!
}
# Autogenerated input type of CreateTaxForm
input CreateTaxFormInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
type: TaxFormTypeEnum!
}
# Autogenerated return type of CreateTaxForm
type CreateTaxFormPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of CreateUserBountiesReport
input CreateUserBountiesReportInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of CreateUserBountiesReport
type CreateUserBountiesReportPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of CreateUserLufthansaAccount
input CreateUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
first_name: String!
last_name: String!
number: String!
}
# Autogenerated return type of CreateUserLufthansaAccount
type CreateUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A currency as defined by ISO 4217
type Currency implements Node {
code: String!
id: ID!
name: String!
}
# Possible currencies codes for bounties
enum CurrencyCode {
USD
XLA
}
# Different entity types for currencycloud payout preferences
enum CurrencycloudBankTransferEntityType {
company
individual
}
# Different payment types for currencycloud payout preferences
enum CurrencycloudBankTransferPaymentType {
priority
regular
}
# A CurrencyCloud Bank Transfer Payout Preference
type CurrencycloudBankTransferPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
id: ID!
name: String
}
# Autogenerated input type of DeleteBiDirectionalJiraIntegration
input DeleteBiDirectionalJiraIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of DeleteBiDirectionalJiraIntegration
type DeleteBiDirectionalJiraIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteJiraWebhook
input DeleteJiraWebhookInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook_id: ID!
}
# Autogenerated return type of DeleteJiraWebhook
type DeleteJiraWebhookPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeletePhabricatorIntegration
input DeletePhabricatorIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of DeletePhabricatorIntegration
type DeletePhabricatorIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteSlackPipeline
input DeleteSlackPipelineInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_pipeline_id: String!
}
# Autogenerated return type of DeleteSlackPipeline
type DeleteSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deleted_slack_pipeline_id: String!
team: Team
}
# Autogenerated input type of DeleteTeamMember
input DeleteTeamMemberInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member_id: ID!
}
# Autogenerated return type of DeleteTeamMember
type DeleteTeamMemberPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deletedMembershipId: ID
errors: Hash
me: User
}
# Autogenerated input type of DeleteTeamSlackIntegration
input DeleteTeamSlackIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_integration_id: ID!
}
# Autogenerated return type of DeleteTeamSlackIntegration
type DeleteTeamSlackIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteUserLufthansaAccount
input DeleteUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of DeleteUserLufthansaAccount
type DeleteUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of DisableTwoFactorAuthentication
input DisableTwoFactorAuthenticationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
totp_code: String!
}
# Autogenerated return type of DisableTwoFactorAuthentication
type DisableTwoFactorAuthenticationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of DismissProgramHealthAcknowledgementMutation
input DismissProgramHealthAcknowledgementMutationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
program_health_acknowledgement_id: ID!
}
# Autogenerated return type of DismissProgramHealthAcknowledgementMutation
type DismissProgramHealthAcknowledgementMutationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
dismissed_program_health_acknowledgement_id: String!
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of EnableTwoFactorAuthentication
input EnableTwoFactorAuthenticationInput {
backup_codes: [String]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
signature: String!
totp_code: String!
totp_secret: String!
}
# Autogenerated return type of EnableTwoFactorAuthentication
type EnableTwoFactorAuthenticationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of EnableUser
input EnableUserInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of EnableUser
type EnableUserPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of EnrollForProgram
input EnrollForProgramInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of EnrollForProgram
type EnrollForProgramPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deleted_recommended_program_edge: TeamEdge
query: Query!
teams_connection: TeamConnection
}
# An error
type Error implements Node {
field: String
id: ID!
message: String!
type: ErrorTypeEnum!
}
# Types of errors that can occur
enum ErrorTypeEnum {
ARGUMENT
AUTHORIZATION
}
# An External Program
type ExternalProgram implements Node {
# The primary key from the database
_id: ID!
about: String
handle: String!
# ID of the object.
id: ID!
name: String!
profile_picture(size: ProfilePictureSizes!): String!
}
# Autogenerated input type of GenerateMfaOtp
input GenerateMfaOtpInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of GenerateMfaOtp
type GenerateMfaOtpPayload {
backup_codes: [String]
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
qrcode: Hash
signature: String
totp_secret: String
}
# Autogenerated input type of GenerateTaxFormUrl
input GenerateTaxFormUrlInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of GenerateTaxFormUrl
type GenerateTaxFormUrlPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A HackeronePayroll Payout Preference
type HackeronePayrollPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# Configuration for the events sent from HackerOne to JIRA
type HackeroneToJiraEventsConfiguration implements Node {
assignee_changes: Boolean!
comments: Boolean!
id: ID!
public_disclosures: Boolean!
rewards: Boolean!
state_changes: Boolean!
team: Team!
}
scalar Hash
# An interface for the common fields on a HackerOne Invitation
interface InvitationInterface {
_id: ID!
}
# User invitation preference type
enum InvitationPreferenceTypeEnum {
always
bounty_only
never
}
# Invitations can be of multiple types
union InvitationUnion = InvitationsSoftLaunch
# The connection type for InvitationUnion.
type InvitationUnionConnection {
# A list of edges.
edges: [InvitationUnionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type InvitationUnionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: InvitationUnion
}
# An invitation to join a private team as a hacker
type InvitationsSoftLaunch implements InvitationInterface, Node {
_id: ID!
expires_at: String
id: ID!
markdown_message: String
message: String
team: Team!
token: String
}
# A JIRA integration for a team
type JiraIntegration implements Node {
assignee: String
base_url: String!
created_at: String!
custom: String
description: String!
id: ID!
issue_type: Int!
labels: String
pid: Int!
summary: String!
team: Team!
updated_at: String!
}
# A JIRA Oauth for a team
type JiraOauth implements Node {
# Assignables for a project
assignables(project_id: Int!): [Hash]
configured: Boolean!
created_at: String!
id: ID!
issue_types: [Hash]
projects: [Hash]
site: String
team: Team!
updated_at: String!
}
# A JIRA webhook for a team
type JiraWebhook implements Node {
created_at: String!
id: ID!
last_event_received_at: String
last_token_issued_at: String
process_assignee_change: Boolean!
process_comment_add: Boolean!
process_priority_change: Boolean!
process_resolution_change: Boolean!
process_status_change: Boolean!
team: Team!
updated_at: String!
}
# Autogenerated input type of LeavePrivateProgram
input LeavePrivateProgramInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of LeavePrivateProgram
type LeavePrivateProgramPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of LockReport
input LockReportInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report_id: ID!
}
# Autogenerated return type of LockReport
type LockReportPayload {
activities: ActivityUnionConnection
activity: ActivitiesComment
# A unique identifier for the client performing the mutation.
clientMutationId: String
new_activity_edge: ActivityUnionEdge
report: Report
}
# Settings for a user's Lufthansa Account
type LufthansaAccount implements Node {
created_at: String!
first_name: String!
id: ID!
last_name: String!
number: String!
updated_at: String!
}
# Autogenerated input type of MarkReportAsNeedsMoreInfo
input MarkReportAsNeedsMoreInfoInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of MarkReportAsNeedsMoreInfo
type MarkReportAsNeedsMoreInfoPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
report_id: ID!
was_successful: Boolean!
}
# Autogenerated input type of MarkReportAsNoise
input MarkReportAsNoiseInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of MarkReportAsNoise
type MarkReportAsNoisePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
was_successful: Boolean!
}
# Autogenerated input type of MarkReportAsSignal
input MarkReportAsSignalInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of MarkReportAsSignal
type MarkReportAsSignalPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
was_successful: Boolean!
}
type Mutation {
acceptInvitation(input: AcceptInvitationInput!): AcceptInvitationPayload
acknowledgeProgramHealthAcknowledgement(input: AcknowledgeProgramHealthAcknowledgementMutationInput!): AcknowledgeProgramHealthAcknowledgementMutationPayload
archiveStructuredScope(input: ArchiveStructuredScopeInput!): ArchiveStructuredScopePayload
createActivityComment(input: CreateActivityCommentInput!): CreateActivityCommentPayload
createBounty(input: CreateBountyInput!): CreateBountyPayload
createBountySuggestion(input: CreateBountySuggestionInput!): CreateBountySuggestionPayload
createCoinbasePayoutPreference(input: CreateCoinbasePayoutPreferenceInput!): CreateCoinbasePayoutPreferencePayload
createCurrencycloudBankTransferPayoutPreference(input: CreateCurrencycloudBankTransferPayoutPreferenceInput!): CreateCurrencycloudBankTransferPayoutPreferencePayload
createJiraOauthUrl(input: CreateJiraOauthUrlInput!): CreateJiraOauthUrlPayload
createJiraWebhookToken(input: CreateJiraWebhookTokenInput!): CreateJiraWebhookTokenPayload
createMailingAddress(input: CreateMailingAddressInput!): CreateMailingAddressPayload
createOrUpdateHackeroneToJiraEventsConfiguration(input: CreateOrUpdateHackeroneToJiraEventsConfigurationInput!): CreateOrUpdateHackeroneToJiraEventsConfigurationPayload
createOrUpdateJiraIntegration(input: CreateOrUpdateJiraIntegrationInput!): CreateOrUpdateJiraIntegrationPayload
createPaypalPreference(input: CreatePaypalPreferenceInput!): CreatePaypalPreferencePayload
createSlackPipeline(input: CreateSlackPipelineInput!): CreateSlackPipelinePayload
createStructuredScope(input: CreateStructuredScopeInput!): CreateStructuredScopePayload
createSurveyAnswer(input: CreateSurveyAnswerInput!): CreateSurveyAnswerPayload
createSwag(input: CreateSwagInput!): CreateSwagPayload
createTaxForm(input: CreateTaxFormInput!): CreateTaxFormPayload
createUserBountiesReport(input: CreateUserBountiesReportInput!): CreateUserBountiesReportPayload
createUserLufthansaAccount(input: CreateUserLufthansaAccountInput!): CreateUserLufthansaAccountPayload
deleteBiDirectionalJiraIntegration(input: DeleteBiDirectionalJiraIntegrationInput!): DeleteBiDirectionalJiraIntegrationPayload
deleteJiraWebhook(input: DeleteJiraWebhookInput!): DeleteJiraWebhookPayload
deletePhabricatorIntegration(input: DeletePhabricatorIntegrationInput!): DeletePhabricatorIntegrationPayload
deleteSlackPipeline(input: DeleteSlackPipelineInput!): DeleteSlackPipelinePayload
deleteTeamMember(input: DeleteTeamMemberInput!): DeleteTeamMemberPayload
deleteTeamSlackIntegration(input: DeleteTeamSlackIntegrationInput!): DeleteTeamSlackIntegrationPayload
deleteUserLufthansaAccount(input: DeleteUserLufthansaAccountInput!): DeleteUserLufthansaAccountPayload
disableTwoFactorAuthentication(input: DisableTwoFactorAuthenticationInput!): DisableTwoFactorAuthenticationPayload
dismissProgramHealthAcknowledgement(input: DismissProgramHealthAcknowledgementMutationInput!): DismissProgramHealthAcknowledgementMutationPayload
enableTwoFactorAuthentication(input: EnableTwoFactorAuthenticationInput!): EnableTwoFactorAuthenticationPayload
enableUser(input: EnableUserInput!): EnableUserPayload
enrollForProgram(input: EnrollForProgramInput!): EnrollForProgramPayload
generateMfaOtp(input: GenerateMfaOtpInput!): GenerateMfaOtpPayload
generateTaxFormUrl(input: GenerateTaxFormUrlInput!): GenerateTaxFormUrlPayload
leavePrivateProgram(input: LeavePrivateProgramInput!): LeavePrivateProgramPayload
lockReport(input: LockReportInput!): LockReportPayload
markReportAsNeedsMoreInfo(input: MarkReportAsNeedsMoreInfoInput!): MarkReportAsNeedsMoreInfoPayload
markReportAsNoise(input: MarkReportAsNoiseInput!): MarkReportAsNoisePayload
markReportAsSignal(input: MarkReportAsSignalInput!): MarkReportAsSignalPayload
rejectInvitation(input: RejectInvitationInput!): RejectInvitationPayload
updateAutomaticInvites(input: UpdateAutomaticInvitesInput!): UpdateAutomaticInvitesPayload
updateBackupCodes(input: UpdateBackupCodesInput!): UpdateBackupCodesPayload
updateInvitationPreferences(input: UpdateInvitationPreferencesInput!): UpdateInvitationPreferencesPayload
updateJiraWebhook(input: UpdateJiraWebhookInput!): UpdateJiraWebhookPayload
updateMe(input: UpdateMeInput!): UpdateMePayload
updatePhabricatorIntegration(input: UpdatePhabricatorIntegrationInput!): UpdatePhabricatorIntegrationPayload
updateReportStateToNeedsMoreInfo(input: UpdateReportStateToNeedsMoreInfoInput!): UpdateReportStateToNeedsMoreInfoPayload
updateReportStructuredScope(input: UpdateReportStructuredScopeInput!): UpdateReportStructuredScopePayload
updateSlackPipeline(input: UpdateSlackPipelineInput!): UpdateSlackPipelinePayload
updateSlackUser(input: UpdateSlackUserInput!): UpdateSlackUserPayload
updateStructuredScope(input: UpdateStructuredScopeInput!): UpdateStructuredScopePayload
updateTeamFancySlackIntegration(input: UpdateTeamFancySlackIntegrationInput!): UpdateTeamFancySlackIntegrationPayload
updateTeamMemberVisibility(input: UpdateTeamMemberVisibilityInput!): UpdateTeamMemberVisibilityPayload
updateTeamSubmissionState(input: UpdateTeamSubmissionStateInput!): UpdateTeamSubmissionStatePayload
updateTeamSubscription(input: UpdateTeamSubscriptionInput!): UpdateTeamSubscriptionPayload
updateTeamWeakness(input: UpdateTeamWeaknessInput!): UpdateTeamWeaknessPayload
updateUserEmail(input: UpdateUserEmailInput!): UpdateUserEmailPayload
updateUserLufthansaAccount(input: UpdateUserLufthansaAccountInput!): UpdateUserLufthansaAccountPayload
updateUserPassword(input: UpdateUserPasswordInput!): UpdateUserPasswordPayload
}
# An object with an ID.
interface Node {
# ID of the object.
id: ID!
}
# Possible directions for sorting a collection
enum OrderDirection {
ASC
DESC
}
# Information about pagination in a connection.
type PageInfo {
# When paginating forwards, the cursor to continue.
endCursor: String
# When paginating forwards, are there more items?
hasNextPage: Boolean!
# When paginating backwards, are there more items?
hasPreviousPage: Boolean!
# When paginating backwards, the cursor to continue.
startCursor: String
}
# The connection type for User.
type ParticipantConnection {
# A list of edges.
edges: [ParticipantWithReputationEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
year_range: [Int]
}
# An edge in a connection.
type ParticipantWithReputationEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: User
# The participant's rank within the team
rank: Int
# The participant's reputation within the team
reputation: Int
}
# A interface for the common fields on an Payout Preference
interface PayoutPreferenceInterface {
_id: ID!
default: Boolean
id: ID!
}
# A user can have payout preferences for different payment services
union PayoutPreferenceUnion = CoinbasePayoutPreferenceType | CurrencycloudBankTransferPayoutPreferenceType | HackeronePayrollPayoutPreferenceType | PaypalPayoutPreferenceType
# A Paypal Payout Preference
type PaypalPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# All available permissions
enum PermissionEnum {
program_management
}
# A Phabricator integration for a team
type PhabricatorIntegration implements Node {
base_url: String
created_at: String!
description: String
id: ID!
process_h1_comment_added: Boolean!
process_h1_status_change: Boolean!
process_phabricator_comment_added: Boolean!
process_phabricator_status_change: Boolean!
project_tags: String
team: Team!
title: String
updated_at: String!
}
# Different possible profile picture sizes
enum ProfilePictureSizes {
# 110x110
large
# 82x82
medium
# 62x62
small
# 260x260
xtralarge
}
# A program_health_acknowledgement for a team_member
type ProgramHealthAcknowledgement implements Node {
acknowledged: Boolean
created_at: String
dismissed: Boolean
id: ID!
reason: ProgramHealthAcknowledgementReasonEnum
team_member: TeamMember!
}
# The connection type for ProgramHealthAcknowledgement.
type ProgramHealthAcknowledgementConnection {
# A list of edges.
edges: [ProgramHealthAcknowledgementEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ProgramHealthAcknowledgementEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: ProgramHealthAcknowledgement
}
# reason which reflect the state of a program health acknowledgement
enum ProgramHealthAcknowledgementReasonEnum {
failed
ok
paused
review
}
# Root entity of the Hackerone Schema
type Query implements Node {
bank_transfer_reference: BankTransferReference
clusters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: ClusterOrder = {direction: ASC, field: BROWSING_FRIENDLY}
): ClusterConnection
external_program(handle: String!): ExternalProgram
id: ID!
me: User
# Fetches an object given its ID.
node(
# ID of the object.
id: ID!
): Node
query: Query!
report(id: Int!): Report @deprecated(reason: "Query for a Report node at the root level is not recommended.")
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
substate: ReportStateEnum
without_scope: Boolean = null
): ReportConnection
resource(url: URI): ResourceInterface
session: Session
severity_calculator: SeverityCalculator
surveys(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
category: SurveyCategoryEnum
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SurveyConnectionType
team(handle: String!): Team @deprecated(reason: "Query for a Team node at the root level is not recommended. Ref T12456")
teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
enrollable: Boolean
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamOrderInput
permissions: [PermissionEnum] = []
): TeamConnection
user(username: String!): User @deprecated(reason: "Query for a User node at the root level is not recommended. Ref T12456")
users(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): UserConnection
}
# Autogenerated input type of RejectInvitation
input RejectInvitationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of RejectInvitation
type RejectInvitationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# A HackerOne report
type Report implements Node, ResourceInterface {
_id: ID!
activities(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
not_types: [ActivityTypes]
order_by: ActivityOrderInput
types: [ActivityTypes]
# A timestamp encoded as a string that. When provided, only activities with a
# updated_at greater than this value will be resolved. Example:
# activities(updated_at_after: "2017-11-30 13:37:12 UTC")
updated_at_after: String
): ActivityConnection
allow_singular_disclosure_after: String
allow_singular_disclosure_at: String
assignee: AssigneeUnion
attachments: [Attachment]
bounties: [Bounty]
bounty_awarded_at: String
bug_reporter_agreed_on_going_public_at: String
cloned_from: Report
closed_at: String
comments_closed: Boolean
created_at: String!
cve_ids: [String]
disclosed_at: String
first_program_activity_at: String
i_can_anc_review: Boolean
id: ID!
latest_activity_at: String
latest_public_activity_at: String
latest_public_activity_of_reporter_at: String
latest_public_activity_of_team_at: String
mediation_requested_at: String
original_report: Report
pre_submission_review_state: String
reference: ID
reference_link: String
reporter: User
severity: Severity
singular_disclosure_allowed: Boolean
singular_disclosure_disabled: Boolean
stage: String
stale: Boolean
state: String
structured_scope: StructuredScope
substate: String!
suggested_bounty: String
summaries: [Summary]
swag: [Swag]
swag_awarded_at: String
team: Team
team_member_agreed_on_going_public_at: String
title: String
triaged_at: String
# A pre-submission trigger that notified the hacker before submission. This
# field is only present for reports filed after February 14, 2016.
triggered_pre_submission_trigger: Trigger
url: URI!
vulnerability_information: String
vulnerability_information_html: String
weakness: Weakness
}
# A interface for the common fields on an HackerOne Report Activity
interface ReportActivityInterface {
attachments: [Attachment]
automated_response: Boolean
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
report: Report
}
# The connection type for Report.
type ReportConnection {
# Groups and counts reports by the severity rating
count_by_severity: [CountBySeverity]!
# A list of edges.
edges: [ReportEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ReportEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Report
}
# Filters which can be used to query reports
enum ReportFilterEnum {
assigned
assigned_to_me
bounty_awarded
going_public_team
going_public_user
hacker_requested_mediation
ineligible_for_bounty
needs_first_program_response
no_bounty_awarded
no_swag_awarded
not_public
public
reporter_is_active
stale
swag_awarded
unassigned
}
# Fields on which a collection of reports can be ordered
enum ReportOrderField {
created_at
id
latest_activity_at
}
input ReportOrderInput {
direction: OrderDirection!
field: ReportOrderField!
}
# Pre submission review states a report can be in
enum ReportPreSubmissionReviewStateEnum {
pre_submission_accepted
pre_submission_needs_more_info
pre_submission_pending
pre_submission_rejected
}
# States a report can be in
enum ReportStateEnum {
closed
duplicate
informative
needs_more_info
new
not_applicable
open
pre_submission
resolved
spam
triaged
}
# The connection type for User.
type ReporterConnection {
# A list of edges.
edges: [UserEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# Represents a type that can be retrieved by a URL.
interface ResourceInterface {
url: URI!
}
# A HackerOne session
type Session implements Node {
csrf_token: String! @deprecated(reason: "This token is used to support legacy operations in HackerOne's frontend")
id: ID!
}
# A HackerOne severity for a report
type Severity implements Node {
_id: ID!
attack_complexity: SeverityAttackComplexityEnum
attack_vector: SeverityAttackVectorEnum
author_type: SeverityAuthorEnum
availability: SeverityAvailabilityEnum
confidentiality: SeverityConfidentialityEnum
created_at: String
id: ID!
integrity: SeverityIntegrityEnum
privileges_required: SeverityPrivilegesRequiredEnum
rating: SeverityRatingEnum
scope: SeverityScopeEnum
score: Float
user_id: Int
user_interaction: SeverityUserInteractionEnum
}
# Severity attack complexity
enum SeverityAttackComplexityEnum {
high
low
}
# Severity attack vector
enum SeverityAttackVectorEnum {
adjacent
local
network
physical
}
# Severity author
enum SeverityAuthorEnum {
Team
User
}
# Severity availability
enum SeverityAvailabilityEnum {
high
low
none
}
# Calculate CVSS Severity score and rating
type SeverityCalculator implements Node {
calculated_max_severity(availability_requirement: SeveritySecurityRequirementEnum, confidentiality_requirement: SeveritySecurityRequirementEnum, integrity_requirement: SeveritySecurityRequirementEnum): SeverityRatingEnum
id: ID!
}
# Severity confidentiality
enum SeverityConfidentialityEnum {
high
low
none
}
# Severity integrity
enum SeverityIntegrityEnum {
high
low
none
}
# Severity privileges required
enum SeverityPrivilegesRequiredEnum {
high
low
none
}
# Severity rating
enum SeverityRatingEnum {
critical
high
low
medium
none
}
# Severity scope
enum SeverityScopeEnum {
changed
unchanged
}
# Severity security requirement rating
enum SeveritySecurityRequirementEnum {
high
low
medium
none
}
# Severity user interaction
enum SeverityUserInteractionEnum {
none
required
}
# SLA types
enum SlaTypeEnum {
first_program_response
report_triage
}
# Slack channel
type SlackChannel implements Node {
# ID of the object.
id: ID!
name: String!
}
# A Slack integration for a team
type SlackIntegration implements Node {
channel: String @deprecated(reason: "this field is not used in our new Slack integration")
channels: [SlackChannel]
id: ID!
should_fetch_slack_channels: Boolean!
should_fetch_slack_users: Boolean!
team: Team!
team_url: String!
users: [SlackUser]
}
# A Slack Pipeline Configuration for notifications
type SlackPipeline implements Node, ResourceInterface {
# The primary key from the database
_id: ID!
channel: String!
descriptive_label: String
id: ID!
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
team: Team!
updated_at: String!
url: URI!
}
# The connection type for SlackPipeline.
type SlackPipelineConnection {
# A list of edges.
edges: [SlackPipelineEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SlackPipelineEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: SlackPipeline
}
# Slack user
type SlackUser implements Node {
# The id provided by Slack
_id: String!
avatar_small: String!
deleted: Boolean!
email: String!
# ID of the object.
id: ID!
name: String!
real_name: String
}
# A static participant for a team
type StaticParticipant implements Node {
_id: ID!
avatar(size: ProfilePictureSizes!): String!
bio: String
external_url: String
id: ID!
name: String!
year: String
}
# The connection type for StaticParticipant.
type StaticParticipantConnection {
# A list of edges.
edges: [StaticParticipantEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type StaticParticipantEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StaticParticipant
}
# A defined scope of a HackerOne program
type StructuredScope implements Node, ResourceInterface {
_id: ID!
archived_at: String
asset_identifier: String!
asset_type: StructuredScopedAssetTypeEnum
availability_requirement: SeveritySecurityRequirementEnum
confidentiality_requirement: SeveritySecurityRequirementEnum
created_at: String!
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
id: ID!
instruction: String
integrity_requirement: SeveritySecurityRequirementEnum
max_severity: SeverityRatingEnum
reference: String
rendered_instruction: String
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReportConnection
structured_scope_versions(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): StructuredScopeVersionConnection
team: Team
updated_at: String
url: URI!
}
# An edge in a connection.
type StructuredScopeEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StructuredScope
}
# A versioned log of a scope of a HackerOne program
type StructuredScopeVersion implements Node, ResourceInterface {
_id: ID!
archived_at: String
created_at: String!
id: ID!
instruction: String
max_severity: String
team: Team
url: URI!
}
# The connection type for StructuredScopeVersion.
type StructuredScopeVersionConnection {
# A list of edges.
edges: [StructuredScopeVersionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type StructuredScopeVersionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StructuredScopeVersion
}
# Structured Scope asset type enum
enum StructuredScopedAssetTypeEnum {
APPLE_STORE_APP_ID
CIDR
DOWNLOADABLE_EXECUTABLES
GOOGLE_PLAY_APP_ID
HARDWARE
OTHER
OTHER_APK
OTHER_IPA
SOURCE_CODE
TESTFLIGHT
URL
WINDOWS_APP_STORE_APP_ID
}
# The connection type for StructuredScope.
type StructuredScopesConnection {
# A list of edges.
edges: [StructuredScopeEdge]
max_updated_at: String
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# Submission states
enum SubmissionStateEnum {
disabled
open
paused
}
# Team subscription action enum
enum SubscriptionActionEnum {
subscribe_to_all
unsubscribe_from_all
}
# A HackerOne summary for a report
type Summary implements Node {
_id: ID!
category: String! @deprecated(reason: "The implementation of this field contains hard to reason about polymorphism")
content: String!
created_at: String!
id: ID!
updated_at: String!
user: User!
}
# A HackerOne survey
type Survey implements Node, ResourceInterface {
category: String!
id: ID!
question: String!
structured_responses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SurveyStructuredResponseConnectionType
url: URI!
}
# Survey categories
enum SurveyCategoryEnum {
invitation_rejection
}
# The connection type for Survey.
type SurveyConnectionType {
# A list of edges.
edges: [SurveyEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SurveyEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Survey
}
# Prepared survey response reasons
type SurveyStructuredResponse implements Node {
_id: ID!
enabled: Boolean!
helper_text: String
id: ID!
reason: String!
survey: Survey
}
# The connection type for SurveyStructuredResponse.
type SurveyStructuredResponseConnectionType {
# A list of edges.
edges: [SurveyStructuredResponseEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SurveyStructuredResponseEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: SurveyStructuredResponse
}
# A HackerOne swag awarded for a report
type Swag implements Node {
_id: ID!
address: Address @deprecated(reason: "This field is deprecated. The preferred way to access this data is using swag.user.address.")
created_at: String
id: ID!
report: Report
sent: Boolean!
team: Team
user: User
}
# The connection type for Swag.
type SwagConnection {
# A list of edges.
edges: [SwagEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type SwagEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Swag
}
# A tax form for a user
type TaxForm implements Node {
created_at: String!
hello_sign_client_id: String
id: ID!
signed_at: String
status: TaxFormStateEnum!
type: TaxFormTypeEnum!
url: String
}
# Status of a tax form
enum TaxFormStateEnum {
expired
needs_review
rejected
requested
unavailable
valid
}
# Type of a tax form
enum TaxFormTypeEnum {
W8BEN
W8BENE
W9
W9Corporate
}
# A HackerOne team
type Team implements Node, ResourceInterface {
# The primary key from the database
_id: ID!
about: String
abuse: Boolean
activities(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
not_types: [ActivityTypes]
order_by: ActivityOrderInput
types: [ActivityTypes]
# A timestamp encoded as a string that. When provided, only activities with a
# updated_at greater than this value will be resolved. Example:
# activities(updated_at_after: "2017-11-30 13:37:12 UTC")
updated_at_after: String
): ActivityConnection
automatic_invites: Boolean
base_bounty: Int
bug_count: Int
child_teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamConnection
common_responses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: CommonResponseOrder = {direction: ASC, field: title}
): CommonResponseConnection
created_at: String
currency: String
fancy_slack_integration: Boolean
fancy_slack_integration_enabled: Boolean!
first_response_time: Float
hackerone_to_jira_events_configuration: HackeroneToJiraEventsConfiguration
handle: String!
has_avatar: Boolean
has_policy: Boolean
i_can_create_jira_webhook: Boolean
i_can_destroy_jira_webhook: Boolean!
i_can_view_base_bounty: Boolean
i_can_view_jira_integration: Boolean
i_can_view_jira_webhook: Boolean
i_can_view_phabricator_integration: Boolean
i_can_view_program_health: Boolean!
i_can_view_reports_resolved: Boolean
i_can_view_weaknesses: Boolean
i_cannot_create_jira_webhook_reasons: [TeamCannotCreateJiraWebhookReasons]!
id: ID!
inbox_views(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamInboxViewOrder = {direction: ASC, field: position}
visible: Boolean
): TeamInboxViewConnection
internet_bug_bounty: Boolean
jira_integration: JiraIntegration
jira_oauth: JiraOauth
jira_phase_3_enabled: Boolean!
jira_webhook: JiraWebhook
maximum_number_of_team_mediation_requests: Float
name: String!
new_staleness_threshold: Int
offers_bounties: Boolean
offers_swag: Boolean
open_soft_launch_invitations(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): InvitationUnionConnection @deprecated(reason: "This should be a generic invitation connection.\n Used interim until generic invitation type is defined")
participants(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
limit: Int = null
year: Int = null
): ParticipantConnection
phabricator_integration: PhabricatorIntegration
policy_html: String
profile_picture(size: ProfilePictureSizes!): String!
report_submission_form_intro: String
report_template: String
reporters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReporterConnection
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
state: ReportStateEnum
substate: ReportStateEnum
violates_minimum_sla: SlaTypeEnum
without_scope: Boolean = null
): ReportConnection
review_requested_at: String
sla_failed_count: Int
sla_missed_count: Int
slack_integration: SlackIntegration
slack_pipelines(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SlackPipelineConnection
state: TeamState!
static_participants(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): StaticParticipantConnection
structured_scopes(
# Returns the elements in the list that come after the specified cursor.
after: String
archived: Boolean = null
asset_type: String = null
# Returns the elements in the list that come before the specified cursor.
before: String
eligible_for_submission: Boolean = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
search: String = null
): StructuredScopesConnection
submission_state: SubmissionStateEnum!
target_signal: Float
team_member_groups(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamMemberGroupConnection
team_members(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamMemberOrder = {direction: ASC, field: username}
): TeamMemberConnection
triage_active: Boolean
triage_time: Float
triaged_staleness_threshold: Int
twitter_handle: String
updated_at: String
url: URI!
weaknesses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
cluster_id: ID = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: WeaknessOrder = {direction: ASC, field: name}
search: String = null
team_weakness_state: [TeamWeaknessStates] = [enabled, disabled, hidden]
): TeamWeaknessConnection
website: String
whitelisted_hackers(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReporterConnection
}
# Different reasons why a team cannot create a jira webhook
enum TeamCannotCreateJiraWebhookReasons {
CANNOT_VIEW
FEATURE_GATED
PROGRAM_PERMISSION_REQUIRED
}
# The connection type for Team.
type TeamConnection {
# A list of edges.
edges: [TeamEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Team
}
# A team report filter preset
type TeamInboxView implements Node {
_id: ID!
assigned_to_group_ids: [Int!]!
assigned_to_user_ids: [Int!]!
built_in: Boolean!
created_at: String!
filters: [ReportFilterEnum!]!
hackathons: [Int!]!
id: ID!
key: String!
name: String!
position: Int!
reporter_ids: [Int!]!
severities: [String!]!
substates: [ReportStateEnum!]!
team: Team!
text_query: String!
updated_at: String!
visible: Boolean!
}
# The connection type for TeamInboxView.
type TeamInboxViewConnection {
# A list of edges.
edges: [TeamInboxViewEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamInboxViewEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamInboxView
}
input TeamInboxViewOrder {
direction: OrderDirection!
field: TeamInboxViewOrderField!
}
# Fields on which a collection of team inbox views can be ordered
enum TeamInboxViewOrderField {
position
}
# A HackerOne team member
type TeamMember implements Node {
# The primary key from the database
_id: ID!
auto_subscribe: Boolean
concealed: Boolean
created_at: String!
i_can_leave_team: Boolean!
id: ID!
permissions: [String]!
slack_user_id: String
team: Team!
user: User!
}
# The connection type for TeamMember.
type TeamMemberConnection {
# A list of edges.
edges: [TeamMemberEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamMemberEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamMember
}
# A HackerOne team member group
type TeamMemberGroup implements Node {
_id: ID!
created_at: String
# ID of the object.
id: ID!
name: String!
permissions: [String]!
}
# The connection type for TeamMemberGroup.
type TeamMemberGroupConnection {
# A list of edges.
edges: [TeamMemberGroupEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type TeamMemberGroupEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamMemberGroup
}
input TeamMemberOrder {
direction: OrderDirection!
field: TeamMemberOrderField!
}
# Fields on which a collection of team members can be ordered
enum TeamMemberOrderField {
username
}
# Fields on which a collection of Teams can be ordered
enum TeamOrderField {
missing_pressure
name
}
input TeamOrderInput {
direction: OrderDirection!
field: TeamOrderField!
}
# Different possible team states
enum TeamState {
da_mode
inactive
public_mode
sandboxed
soft_launched
}
# Team configuration of a weakness
type TeamWeakness implements Node {
id: ID!
instruction: String
state: TeamWeaknessStates
team: Team!
weakness: Weakness!
}
# The connection type for Weakness.
type TeamWeaknessConnection {
# A list of edges.
edges: [TeamWeaknessEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamWeaknessEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Weakness
team_weakness: TeamWeakness
}
# Possible states of how a weakness can be configured for a team
enum TeamWeaknessStates {
disabled
enabled
hidden
}
# A HackerOne trigger
type Trigger implements Node {
_id: ID!
id: ID!
title: String!
}
# Tshirt size
enum TshirtSizeEnum {
M_Large
M_Medium
M_Small
M_XLarge
M_XXLarge
W_Large
W_Medium
W_Small
W_XLarge
W_XXLarge
}
# Represents a RFC compliant URI string. It is often used to fetch an object.
scalar URI
# Autogenerated input type of UpdateAutomaticInvites
input UpdateAutomaticInvitesInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
enabled: Boolean!
handle: String!
}
# Autogenerated return type of UpdateAutomaticInvites
type UpdateAutomaticInvitesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateBackupCodes
input UpdateBackupCodesInput {
backup_codes: [String]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
signature: String!
totp_code: String!
totp_secret: String!
}
# Autogenerated return type of UpdateBackupCodes
type UpdateBackupCodesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of UpdateInvitationPreferences
input UpdateInvitationPreferencesInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
invitation_preference: InvitationPreferenceTypeEnum!
}
# Autogenerated return type of UpdateInvitationPreferences
type UpdateInvitationPreferencesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdateJiraWebhook
input UpdateJiraWebhookInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook_id: ID!
process_assignee_change: Boolean
process_comment_add: Boolean
process_priority_change: Boolean
process_resolution_change: Boolean
process_status_change: Boolean
}
# Autogenerated return type of UpdateJiraWebhook
type UpdateJiraWebhookPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook: JiraWebhook!
}
# Autogenerated input type of UpdateMe
input UpdateMeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
tshirt_size: String!
}
# Autogenerated return type of UpdateMe
type UpdateMePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdatePhabricatorIntegration
input UpdatePhabricatorIntegrationInput {
api_token: String
base_url: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
description: String
process_h1_comment_added: Boolean
process_h1_status_change: Boolean
process_phabricator_comment_added: Boolean
process_phabricator_status_change: Boolean
team_id: ID!
title: String
}
# Autogenerated return type of UpdatePhabricatorIntegration
type UpdatePhabricatorIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateReportStateToNeedsMoreInfo
input UpdateReportStateToNeedsMoreInfoInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of UpdateReportStateToNeedsMoreInfo
type UpdateReportStateToNeedsMoreInfoPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report: Report
}
# Autogenerated input type of UpdateReportStructuredScope
input UpdateReportStructuredScopeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report_id: ID!
structured_scope_id: ID
}
# Autogenerated return type of UpdateReportStructuredScope
type UpdateReportStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report: Report
}
# Autogenerated input type of UpdateSlackPipeline
input UpdateSlackPipelineInput {
channel: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
descriptive_label: String
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
slack_pipeline_id: ID!
}
# Autogenerated return type of UpdateSlackPipeline
type UpdateSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
slack_pipeline: SlackPipeline!
}
# Autogenerated input type of UpdateSlackUser
input UpdateSlackUserInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_user_id: String!
team_member_id: ID!
}
# Autogenerated return type of UpdateSlackUser
type UpdateSlackUserPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member: TeamMember!
}
# Autogenerated input type of UpdateStructuredScope
input UpdateStructuredScopeInput {
asset_identifier: String
availability_requirement: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
confidentiality_requirement: String
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
instruction: String
integrity_requirement: String
reference: String
structured_scope_id: ID!
}
# Autogenerated return type of UpdateStructuredScope
type UpdateStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
query: Query
structured_scope: StructuredScope
}
# Autogenerated input type of UpdateTeamFancySlackIntegration
input UpdateTeamFancySlackIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
fancy_slack_integration: Boolean!
team_id: ID!
}
# Autogenerated return type of UpdateTeamFancySlackIntegration
type UpdateTeamFancySlackIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of UpdateTeamMemberVisibility
input UpdateTeamMemberVisibilityInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
concealed: Boolean!
team_member_id: ID!
}
# Autogenerated return type of UpdateTeamMemberVisibility
type UpdateTeamMemberVisibilityPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team_member: TeamMember
}
# Autogenerated input type of UpdateTeamSubmissionState
input UpdateTeamSubmissionStateInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
submission_state: SubmissionStateEnum!
}
# Autogenerated return type of UpdateTeamSubmissionState
type UpdateTeamSubmissionStatePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateTeamSubscription
input UpdateTeamSubscriptionInput {
action: SubscriptionActionEnum
auto_subscribe: Boolean!
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member_id: ID!
}
# Autogenerated return type of UpdateTeamSubscription
type UpdateTeamSubscriptionPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team_member: TeamMember
}
# Autogenerated input type of UpdateTeamWeakness
input UpdateTeamWeaknessInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
instruction: String
state: TeamWeaknessStates!
team_weakness_id: ID!
}
# Autogenerated return type of UpdateTeamWeakness
type UpdateTeamWeaknessPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
query: Query
team_weakness: TeamWeakness
}
# Autogenerated input type of UpdateUserEmail
input UpdateUserEmailInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
email: String!
password: String!
}
# Autogenerated return type of UpdateUserEmail
type UpdateUserEmailPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of UpdateUserLufthansaAccount
input UpdateUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
first_name: String!
last_name: String!
number: String!
}
# Autogenerated return type of UpdateUserLufthansaAccount
type UpdateUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdateUserPassword
input UpdateUserPasswordInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
current_password: String!
password: String!
password_confirmation: String!
}
# Autogenerated return type of UpdateUserPassword
type UpdateUserPasswordPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A HackerOne user
type User implements Node, ResourceInterface {
_id: ID!
address: Address
authentication_service: AuthenticationServiceEnum!
badges(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BadgesUsersConnection
bio: String
bounties(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
currency: CurrencyCode = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BountyConnection
created_at: String!
demo_hacker: Boolean!
disabled: Boolean!
duplicate_users(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): UserConnection
email: String
i_can_update_username: Boolean
id: ID!
impact: Float
impact_percentile: Float
invitation_preference: InvitationPreferenceTypeEnum
location: String
lufthansa_account: LufthansaAccount
member_of_verified_team: Boolean
membership(team_handle: String!): TeamMember
memberships(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamMemberConnection
name: String
next_update_username_date: String
otp_backup_codes: [String]
payout_preferences: [PayoutPreferenceUnion]
profile_picture(size: ProfilePictureSizes!): String!
profile_pictures: Hash! @deprecated(reason: "Returns all the possible profile pictures instead of just the one you want use .profile_picture instead.")
program_health_acknowledgements(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ProgramHealthAcknowledgementConnection
rank: Int
remaining_reports(team_handle: String!): Int
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
handle: String
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
substate: ReportStateEnum
without_scope: Boolean = null
): ReportConnection
reputation: Int
signal: Float
signal_percentile: Float
soft_launch_invitation(team_handle: String!): InvitationsSoftLaunch
swag(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SwagConnection
tax_form: TaxForm
teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
enrollable: Boolean
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamOrderInput
permissions: [PermissionEnum] = []
): TeamConnection
totp_enabled: Boolean
totp_supported: Boolean
triage_user: Boolean
tshirt_size: TshirtSizeEnum
unconfirmed_email: String
url: URI!
username: String!
website: String
whitelisted_teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamConnection
}
# The connection type for User.
type UserConnection {
# A list of edges.
edges: [UserEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type UserEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: User
}
# The type of vulnerability on a HackerOne report
type Weakness implements Node {
_id: ID!
clusters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ClusterConnection
created_at: String!
description: String
external_id: String
id: ID!
name: String!
updated_at: String!
}
input WeaknessOrder {
direction: OrderDirection!
field: WeaknessOrderField!
}
# Fields on which a collection of weaknesses can be ordered
enum WeaknessOrderField {
name
}
graphql-ruby-1.11.10/benchmark/run.rb 0000664 0000000 0000000 00000011317 14141214530 0017351 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
TESTING_INTERPRETER = true
require "graphql"
require "jazz"
require "benchmark/ips"
require "ruby-prof"
require "memory_profiler"
module GraphQLBenchmark
QUERY_STRING = GraphQL::Introspection::INTROSPECTION_QUERY
DOCUMENT = GraphQL.parse(QUERY_STRING)
SCHEMA = Jazz::Schema
BENCHMARK_PATH = File.expand_path("../", __FILE__)
CARD_SCHEMA = GraphQL::Schema.from_definition(File.read(File.join(BENCHMARK_PATH, "schema.graphql")))
ABSTRACT_FRAGMENTS = GraphQL.parse(File.read(File.join(BENCHMARK_PATH, "abstract_fragments.graphql")))
ABSTRACT_FRAGMENTS_2 = GraphQL.parse(File.read(File.join(BENCHMARK_PATH, "abstract_fragments_2.graphql")))
BIG_SCHEMA = GraphQL::Schema.from_definition(File.join(BENCHMARK_PATH, "big_schema.graphql"))
BIG_QUERY = GraphQL.parse(File.read(File.join(BENCHMARK_PATH, "big_query.graphql")))
FIELDS_WILL_MERGE_SCHEMA = GraphQL::Schema.from_definition("type Query { hello: String }")
FIELDS_WILL_MERGE_QUERY = GraphQL.parse("{ #{Array.new(5000, "hello").join(" ")} }")
module_function
def self.run(task)
Benchmark.ips do |x|
case task
when "query"
x.report("query") { SCHEMA.execute(document: DOCUMENT) }
when "validate"
x.report("validate - introspection ") { CARD_SCHEMA.validate(DOCUMENT) }
x.report("validate - abstract fragments") { CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS) }
x.report("validate - abstract fragments 2") { CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS_2) }
x.report("validate - big query") { BIG_SCHEMA.validate(BIG_QUERY) }
x.report("validate - fields will merge") { FIELDS_WILL_MERGE_SCHEMA.validate(FIELDS_WILL_MERGE_QUERY) }
else
raise("Unexpected task #{task}")
end
end
end
def self.profile
# Warm up any caches:
SCHEMA.execute(document: DOCUMENT)
# CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS)
res = nil
result = RubyProf.profile do
# CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS)
res = SCHEMA.execute(document: DOCUMENT)
end
# printer = RubyProf::FlatPrinter.new(result)
# printer = RubyProf::GraphHtmlPrinter.new(result)
printer = RubyProf::FlatPrinterWithLineNumbers.new(result)
printer.print(STDOUT, {})
end
# Adapted from https://github.com/rmosolgo/graphql-ruby/issues/861
def self.profile_large_result
schema = ProfileLargeResult::Schema
document = ProfileLargeResult::ALL_FIELDS
Benchmark.ips do |x|
x.report("Querying for #{ProfileLargeResult::DATA.size} objects") {
schema.execute(document: document)
}
end
result = RubyProf.profile do
schema.execute(document: document)
end
printer = RubyProf::FlatPrinter.new(result)
# printer = RubyProf::GraphHtmlPrinter.new(result)
# printer = RubyProf::FlatPrinterWithLineNumbers.new(result)
printer.print(STDOUT, {})
report = MemoryProfiler.report do
schema.execute(document: document)
end
report.pretty_print
end
module ProfileLargeResult
DATA = 1000.times.map {
{
id: SecureRandom.uuid,
int1: SecureRandom.random_number(100000),
int2: SecureRandom.random_number(100000),
string1: SecureRandom.base64,
string2: SecureRandom.base64,
boolean1: SecureRandom.random_number(1) == 0,
boolean2: SecureRandom.random_number(1) == 0,
int_array: 10.times.map { SecureRandom.random_number(100000) },
string_array: 10.times.map { SecureRandom.base64 },
boolean_array: 10.times.map { SecureRandom.random_number(1) == 0 },
}
}
class FooType < GraphQL::Schema::Object
field :id, ID, null: false
field :int1, Integer, null: false
field :int2, Integer, null: false
field :string1, String, null: false
field :string2, String, null: false
field :boolean1, Boolean, null: false
field :boolean2, Boolean, null: false
field :string_array, [String], null: false
field :int_array, [Integer], null: false
field :boolean_array, [Boolean], null: false
end
class QueryType < GraphQL::Schema::Object
description "Query root of the system"
field :foos, [FooType], null: false, description: "Return a list of Foo objects"
def foos
DATA
end
end
class Schema < GraphQL::Schema
query QueryType
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
end
ALL_FIELDS = GraphQL.parse <<-GRAPHQL
{
foos {
id
int1
int2
string1
string2
boolean1
boolean2
stringArray
intArray
booleanArray
}
}
GRAPHQL
end
end
graphql-ruby-1.11.10/benchmark/schema.graphql 0000664 0000000 0000000 00000003370 14141214530 0021040 0 ustar 00root root 0000000 0000000 # A big schema for testing
type Query {
node(id: ID!): Node
}
interface Node {
id: ID!
}
interface Node2 {
id: ID
}
interface Commentable {
id: ID!
comments: [Comment!]!
}
interface Named {
name: String!
}
type Comment implements Node {
author: Player
body: String!
id: ID!
}
type Card implements Node, Commentable, Node2, Named {
name: String!
converted_mana_cost: Int!
mana_cost: String!
colors: [Color!]!
power: Int
toughness: Int
rules_text: String!
id: ID!
comments: [Comment!]!
}
type Printing implements Node, Commentable, Node2 {
card: Card!
expansion: Expansion!
rarity: Rarity!
artist: Artist!
id: ID!
comments: [Comment!]!
}
type Expansion implements Node, Commentable, Named {
name: String!
code: String!
printings: [Printing!]!
block: Block!
id: ID!
comments: [Comment!]!
}
type Block implements Node, Commentable, Named {
name: String!
expansions: [Expansion!]!
id: ID!
comments: [Comment!]!
}
# Eg shard, guild, clan
type Watermark implements Node, Commentable, Named {
name: String!
cards: [Card!]!
colors: [Color!]!
id: ID!
comments: [Comment!]!
}
type Artist implements Node, Commentable, Named {
name: String!
printings: [Printing!]!
id: ID!
comments: [Comment!]!
}
type Player implements Node, Commentable, Named {
name: String!
decks: [Deck!]!
id: ID!
comments: [Comment!]!
}
type Deck implements Node, Commentable, Named {
name: String!
colors: [Color!]!
slots: [Slot!]!
id: ID!
comments: [Comment!]!
}
type Slot implements Node, Commentable {
deck: Deck!
card: Card!
id: ID!
comments: [Comment!]!
}
enum Color {
WHITE
BLUE
BLACK
RED
GREEN
COLORLESS
}
enum Rarity {
COMMON
UNCOMMON
RARE
MYTHIC_RARE
TIMESHIFTED
}
graphql-ruby-1.11.10/cop/ 0000775 0000000 0000000 00000000000 14141214530 0015044 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/cop/no_focus_cop.rb 0000664 0000000 0000000 00000000661 14141214530 0020050 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
# Make sure no tests are focused, from https://github.com/rubocop-hq/rubocop/issues/3773#issuecomment-420662102
class NoFocusCop < RuboCop::Cop::Cop
MSG = 'Remove `focus` from tests.'
def_node_matcher :focused?, <<-MATCHER
(send nil? :focus)
MATCHER
def on_send(node)
return unless focused?(node)
add_offense node
end
end
end
graphql-ruby-1.11.10/cop/none_without_block_cop.rb 0000664 0000000 0000000 00000001642 14141214530 0022131 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
# A custom Rubocop rule to catch uses of `.none?` without a block.
#
# @see https://github.com/rmosolgo/graphql-ruby/pull/2090
class NoneWithoutBlockCop < RuboCop::Cop::Cop
MSG = <<-MD
Instead of `.none?` without a block:
- Use `.empty?` to check for an empty collection (faster)
- Add a block to explicitly check for `false` (more clear)
Run `-a` to replace this with `.empty?`.
MD
def on_block(node)
# Since this method was called with a block, it can't be
# a case of `.none?` without a block
ignore_node(node.send_node)
end
def on_send(node)
if !ignored_node?(node) && node.method_name == :none? && node.arguments.size == 0
add_offense(node)
end
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.location.selector, "empty?")
end
end
end
end
graphql-ruby-1.11.10/gemfiles/ 0000775 0000000 0000000 00000000000 14141214530 0016056 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/gemfiles/mongoid_6.gemfile 0000664 0000000 0000000 00000000332 14141214530 0021267 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "mongoid", "~> 6.4.1"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/mongoid_7.gemfile 0000664 0000000 0000000 00000000332 14141214530 0021270 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "mongoid", "~> 7.0.1"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/rails_3.2.gemfile 0000664 0000000 0000000 00000000655 14141214530 0021112 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "3.2.22.5", require: "rails/all"
gem "activerecord", "~> 3.2.21"
gem "actionpack", "~> 3.2.21"
gem "test-unit"
gem "sqlite3", "~> 1.3.6", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/rails_4.2.gemfile 0000664 0000000 0000000 00000000671 14141214530 0021111 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 4.2", require: "rails/all"
gem "activerecord", "~> 4.2.4"
gem "actionpack", "~> 4.2.4"
gem "concurrent-ruby", "~> 1.0"
gem "sqlite3", "~> 1.3.6", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/rails_5.2_postgresql.gemfile 0000664 0000000 0000000 00000000425 14141214530 0023372 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 5.2.0", require: "rails/all"
gem "pg", platform: :ruby
gem "sequel"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/rails_6.0.gemfile 0000664 0000000 0000000 00000000535 14141214530 0021110 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 6.0.0", require: "rails/all"
gem "sqlite3", "~> 1.4", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gemspec path: "../"
graphql-ruby-1.11.10/gemfiles/rails_master.gemfile 0000664 0000000 0000000 00000000550 14141214530 0022075 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", github: "rails/rails", require: "rails/all"
gem 'sqlite3', "~> 1.4", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gemspec path: "../"
graphql-ruby-1.11.10/graphql-ruby.png 0000664 0000000 0000000 00000010340 14141214530 0017404 0 ustar 00root root 0000000 0000000 PNG
IHDR g O ۢ sBIT|d pHYs a a?i tEXtSoftware www.inkscape.org< ]IDATxkTՕ֣i@^VuKv!Hd ia,A2fEdYc|A,i߈(N&jpdfT59Uz=hn=.tϚszw9)f6I2"&{R6ZkL~")J=MC*O͋Y) v)VކT(>ރXPX_4\yMwD˳qYh脯PZtW/Z{ˡrl ܑG$zi Ҿm#cCt3/؛MkRlɟP۸3RlQi k<&^@juJ;
p&FK@
0㿺dyC!fP+kf|]Ʒh#J16XYzQ6X kl!ӬO2ŋ4F]qII[5-z(vQ!$dx+ .Tm
YsiAhiR7?wZ0@$'ކI YPiv$*,)Ib C_L_?brGKĊ;%g]iil~
1 Cb.
/V]]ўWH%TN$"i 2֏HfƦ`SJ{ ]Pg5Я\ič7M9OEO5D|KM̋)^
RASQpIJL{9^fsw&Q.Pd(PZg>IfyxυLi>-^!'6^E@J z|op:× W?<iٲ3R_ a5l%fؿu_˞VM,bPe] ibbi.Iq.Пfur?._pPDeoR#(69S9\wS_ݶ#[&m_)2~]>5u?4\|
߀oQ(6p$fy0^ZCCoRNg+ǹ@/õpf_hN:=^?.iĽ
Wv
Hy`SngߟKvn$h?ygx;^Εz7+߽?zfR^$CR:"G@zSܦac{ꊄ <_I(T,Ćj,e*Z_pi&hi/vw۪igtF$ dҠs">;&Nw겅~xXŠ
jCX;/leXnLLvU /WN^bX&,诳v"ƌy1KA_LoX^pŽPLT~n4^EJuB8cZ^i:,yhGN; Mвbx}/}.GlBJ?DڜHΰ^0EDpUE,ٽ5/z6ۉ\FUK[ԓr+.FeJ/;> zfljA
X݂Ph wh}rZj~"*w7 Hm?O/ZO5i9/z}+{Z4:CTBXS
0*\^ԚZpM9h I`s Vc)*R(CzGEfyF!&`Qb@a[/K.L5MIq >D^Yf2Bϴ#̤v #Vl8+0%l̄BDpu?I++W] ݅|,R1PJգ|=-ٟWg}I13! G.3btEQ'1D%j&@ki,eYhK菠O*48J ^֘EԒHm;Q~kùH}ٴai-ӺŬxUc6HobPP[[x ӣWzS찕aVDa c$Dy@BUcŪQgۧdF۟VN@X]ԦBUeL(_Cʑ@t)@&/9mj}JѵDž M5b:n'_ 4FB9pM>eMWu$>5i=8̳T
C4@tý׀^+ٝ<W^Lb,1z~Z(K
6 BeMO%
ٛzVh R0jd^#6Eo:~uÜf|C61*\
,ştEC4D/X%(QӰ.R|$fvttHV(p[*ZY7yӌoPdjK3R)V
qUB
1:߸g5wK*A%SuBuwm ކ{ ${k8%ow @>1dġ79Jx!?'nቮ"FDo()l^>語hCmU'bn&493鬫z|!}ij*U\1_>[Y7yqCgOe*\WT #xHr3vnGΝdr 2i|UE\_*1e7x1.7EB/V҇JU{-`%W4^Ttyż+[ԛ+MpA56Se-߭e0(*F GÖ9E͘3m%$}`%NC=w [~䨥Ce*rz/^e(H^8mG9hah-;N[1#bb,qu^_
[HRF&2xN3+|%僤®4=Wz"MTa#u }%-T߰nP|)rVq`g)A9kV`j~pĺ;>A2 zʛhG#tLȁ&^IYYlv"3ʺCǺ#|S7
:\8f!(u_sqͱFB1WĸtCOqIHs#}ǚ8@AGƯT$;3fIB:?7hᘓ=[1#8 ]mu|<
1pלX__'*IuU.TʳP@%WՁK+APnb@gbЗbú.)*ܻãW4_,ĚvutWAL\U'c EȊЀ[cb@?9iz^;:6D>ʜq@gx@,AAGnj/LP̋z]Ҩݕ)& } !rH#Ϣ(gMd@~!v/L $}}(ʳMeVN %["|C1(1(qs2~
BK&Jr
K@ѿ6P0(Фc.}@"̎-9͟K59ݜ3YؒgB6pk}0eQ>F:q}+r4 IENDB` graphql-ruby-1.11.10/graphql-ruby.svg 0000664 0000000 0000000 00000002404 14141214530 0017421 0 ustar 00root root 0000000 0000000
graphql-ruby-1.11.10/graphql.gemspec 0000664 0000000 0000000 00000004617 14141214530 0017276 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
require "graphql/version"
require "date"
Gem::Specification.new do |s|
s.name = "graphql"
s.version = GraphQL::VERSION
s.date = Date.today.to_s
s.summary = "A GraphQL language and runtime for Ruby"
s.description = "A plain-Ruby implementation of GraphQL."
s.homepage = "https://github.com/rmosolgo/graphql-ruby"
s.authors = ["Robert Mosolgo"]
s.email = ["rdmosolgo@gmail.com"]
s.license = "MIT"
s.required_ruby_version = ">= 2.2.0" # bc `.to_sym` used on user input
s.metadata = {
"homepage_uri" => "https://graphql-ruby.org",
"changelog_uri" => "https://github.com/rmosolgo/graphql-ruby/blob/master/CHANGELOG.md",
"source_code_uri" => "https://github.com/rmosolgo/graphql-ruby",
"bug_tracker_uri" => "https://github.com/rmosolgo/graphql-ruby/issues",
"mailing_list_uri" => "https://tinyletter.com/graphql-ruby",
}
s.files = Dir["{lib}/**/*", "MIT-LICENSE", "readme.md", ".yardopts"]
s.add_development_dependency "benchmark-ips"
s.add_development_dependency "codeclimate-test-reporter", "~>0.4"
s.add_development_dependency "concurrent-ruby", "~>1.0"
s.add_development_dependency "guard", "~> 2.12"
s.add_development_dependency "guard-minitest", "~> 2.4"
s.add_development_dependency "guard-rake"
s.add_development_dependency "guard-rubocop"
s.add_development_dependency "listen", "~> 3.0.0"
s.add_development_dependency "memory_profiler"
# Remove this limit when minitest-reports is compatible
# https://github.com/kern/minitest-reporters/pull/220
s.add_development_dependency "minitest", "~> 5.9.0"
s.add_development_dependency "minitest-focus", "~> 1.1"
s.add_development_dependency "minitest-reporters", "~>1.0"
s.add_development_dependency "racc", "~> 1.4"
s.add_development_dependency "rake", "~> 12"
s.add_development_dependency "rubocop", "0.68" # for Ruby 2.2 enforcement
# following are required for relay helpers
s.add_development_dependency "appraisal"
# required for upgrader
s.add_development_dependency "parser"
# website stuff
s.add_development_dependency "jekyll"
s.add_development_dependency "yard"
s.add_development_dependency "jekyll-algolia" if RUBY_VERSION >= '2.4.0'
s.add_development_dependency "jekyll-redirect-from" if RUBY_VERSION >= '2.4.0'
s.add_development_dependency "m", "~> 1.5.0"
end
graphql-ruby-1.11.10/guides/ 0000775 0000000 0000000 00000000000 14141214530 0015543 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/CNAME 0000664 0000000 0000000 00000000021 14141214530 0016302 0 ustar 00root root 0000000 0000000 graphql-ruby.org
graphql-ruby-1.11.10/guides/_config.yml 0000664 0000000 0000000 00000000714 14141214530 0017674 0 ustar 00root root 0000000 0000000 title: GraphQL Ruby
baseurl: ""
url: "https://graphql-ruby.org"
exclude:
- .gitignore
keep_files: ["api-doc", ".git"]
# Build settings
markdown: kramdown
highlighter: rouge
kramdown:
auto_ids: true
hard_wrap: false
input: GFM
defaults:
-
scope:
path: ""
values:
layout: "default"
algolia:
application_id: '8VO8708WUV'
index_name: 'prod_graphql_ruby'
plugins:
- jekyll-algolia
- jekyll-redirect-from
graphql-ruby-1.11.10/guides/_layouts/ 0000775 0000000 0000000 00000000000 14141214530 0017402 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/_layouts/default.html 0000664 0000000 0000000 00000003340 14141214530 0021714 0 ustar 00root root 0000000 0000000
{% if page.section contains "GraphQL" %}
{{ page.section }} - {{ page.title }}
{% else %}
GraphQL - {{ page.title }}
{% endif %}
graphql-ruby-1.11.10/guides/_plugins/ 0000775 0000000 0000000 00000000000 14141214530 0017363 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/_plugins/api_doc.rb 0000664 0000000 0000000 00000005433 14141214530 0021313 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require_relative "../../lib/graphql/version"
module GraphQLSite
API_DOC_ROOT = "/api-doc/#{GraphQL::VERSION}/"
module APIDoc
def api_doc(input)
if !input.start_with?("GraphQL")
ruby_ident = "GraphQL::#{input}"
else
ruby_ident = input
end
doc_path = ruby_ident
.gsub("::", "/") # namespaces
.sub(/#(.+)$/, "#\\1-instance_method") # instance methods
.sub(/\.(.+)$/, "#\\1-class_method") # class methods
%|#{input}|
end
def link_to_img(img_path, img_title)
full_img_path = "#{@context.registers[:site].baseurl}#{img_path}"
<<-HTML
HTML
end
end
class APIDocRoot < Liquid::Tag
def render(context)
API_DOC_ROOT
end
end
class OpenAnIssue < Liquid::Tag
def initialize(tag_name, issue_info, tokens)
title, body = issue_info.split(",")
# remove whitespace and quotes if value is present
@title = strip_arg(title)
@body = strip_arg(body)
end
def render(context)
%|open an issue|
end
private
def strip_arg(text)
text && text.strip[1..-2]
end
end
# Build a URL relative to `site.baseurl`,
# asserting that the page exists.
class InternalLink < Liquid::Tag
GUIDES_ROOT = "guides/"
def initialize(tag_name, guide_info, tokens)
text, path = guide_info.split(",")
# remove whitespace and quotes if value is present
@text = strip_arg(text)
@path = strip_arg(path)
if @path && @path.start_with?("/")
@path = @path[1..-1]
end
if !exist?(@path)
raise "Internal link failed, couldn't find file for: #{path}"
end
end
def render(context)
<<-HTML.chomp
#{@text}
HTML
end
private
def strip_arg(text)
text && text.strip[1..-2]
end
POSSIBLE_EXTENSIONS = [".html", ".md"]
def exist?(path)
filepath = GUIDES_ROOT + path.split("#").first
filepath = filepath.sub(".html", "")
POSSIBLE_EXTENSIONS.any? { |ext| File.exist?(filepath + ext) }
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)
graphql-ruby-1.11.10/guides/_sass/ 0000775 0000000 0000000 00000000000 14141214530 0016653 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/_sass/reset.scss 0000664 0000000 0000000 00000002102 14141214530 0020665 0 ustar 00root root 0000000 0000000 /* 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;
}
graphql-ruby-1.11.10/guides/_tasks/ 0000775 0000000 0000000 00000000000 14141214530 0017027 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/_tasks/site.rb 0000664 0000000 0000000 00000013403 14141214530 0020321 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "yard"
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")
# 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
system("yardoc")
# 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}")
mkdir_p push_dest
mkdir_p local_dest
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: [:build_doc] do
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
graphql-ruby-1.11.10/guides/authorization/ 0000775 0000000 0000000 00000000000 14141214530 0020443 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/authorization/accessibility.md 0000664 0000000 0000000 00000005344 14141214530 0023622 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Accessibility
desc: Reject queries from unauthorized users if they access certain parts of the schema.
index: 2
---
__NOTE:__ This kind of authorization is deprecated and isn't supported by the {% internal_link "forthcoming GraphQL runtime", "/queries/interpreter" %} because it's too slow.
With GraphQL-Ruby, you can inspect an incoming query, and return a custom error if that query accesses some unauthorized parts of the schema.
This is different from {% internal_link "visibility", "/authorization/visibility" %}, where unauthorized parts of the schema are treated as non-existent. It's also different from {% internal_link "authorization", "/authorization/authorization" %}, which makes checks _while running_, instead of _before running_.
## Opt-In
To use this kind of authorization, you must add a query analyzer:
```ruby
class MySchema < GraphQL::Schema
# Set up ahead-of-time `accessible?` authorization
query_analyzer GraphQL::Authorization::Analyzer
end
```
## Preventing Access
You can override some `.accessible?(context)` methods to prevent access to certain members of the schema:
- Type and mutation classes have a `.accessible?(context)` class method
- Arguments and fields have a `.accessible?(context)` instance method
These methods are called with the query context, based on the hash you pass as `context:`.
Whenever that method is implemented to return `false`, the currently-checked field will be collected as inaccessible. For example:
```ruby
class BaseField < GraphQL::Schema::Field
def initialize(preview:, **kwargs, &block)
@preview = preview
super(**kwargs, &block)
end
# If this field was marked as preview, hide it unless the current viewer can see previews.
def accessible?(context)
if @preview && !context[:viewer].can_preview?
false
else
super
end
end
end
```
Now, any fields created with `field(..., preview: true)` will be _visible_ to everyone, but only accessible to users where `.can_preview?` is `true`.
## Adding an Error
By default, GraphQL-Ruby will return a simple error to the client if any `.accessible?` checks return false.
You can customize this behavior by overriding {{ "Schema.inaccessible_fields" | api_docs }}, for example:
```ruby
class MySchema < GraphQL::Schema
# If you have a custom `permission_level` setting on your `GraphQL::Field` class,
# you can access it here:
def self.inaccessible_fields(error)
required_permissions = error.fields.map(&:permission_level).uniq
# Return a custom error
GraphQL::AnalysisError.new("You need certain permissions: #{required_permissions.join(", ")}")
end
end
```
Then, your custom error will be added to the response instead of the default one.
graphql-ruby-1.11.10/guides/authorization/authorization.md 0000664 0000000 0000000 00000005661 14141214530 0023675 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Authorization
desc: During execution, check if the current user has permission to access retrieved objects.
index: 3
---
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.
## Adding Authorization Checks
Schema members have `authorized?` methods which will be called during execution:
- Type classes have `.authorized?(object, context)` class methods
- Fields have `#authorized?(object, args, context)` instance methods
- Arguments have `#authorized?(object, arg_value, context)` instance methods
These methods are called with:
- `object`: the object from your application which was returned from a field
- `args`/`arg_value`: The arguments for a field, or the value of an argument
- `context`: the query context, based on the hash passed as `context:`
When you implement this method to return `false`, the query will be halted, for example:
```ruby
class Types::Friendship < Types::BaseObject
# You can only see the details on a `Friendship`
# if you're one of the people involved in it.
def self.authorized?(object, context)
super && (object.to_friend == context[:viewer] || object.from_friend == context[:viewer])
end
end
```
(Always call `super` to get the default checks, too.)
Now, whenever an object of type `Friendship` is going to be returned to the client, it will first go through the `.authorized?` method. If that method returns false, the field will get `nil` instead of the original object, and you may handle that case with an error (see below).
## 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:
```ruby
class MySchema < GraphQL::Schema
# Override this hook to handle cases when `authorized?` returns false for an object:
def self.unauthorized_object(error)
# Add a top-level error to the response instead of returning nil:
raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
```
Now, the custom hook will be called instead of the default one.
If `.unauthorized_object` returns a non-`nil` object (and doesn't `raise` an error), then that object will be used in place of the unauthorized object.
A similar hook is available for unauthorized fields:
```ruby
class MySchema < GraphQL::Schema
# Override this hook to handle cases when `authorized?` returns false for a field:
def self.unauthorized_field(error)
# Add a top-level error to the response instead of returning nil:
raise GraphQL::ExecutionError, "The field #{error.field.graphql_name} on an object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
```
graphql-ruby-1.11.10/guides/authorization/can_can_integration.md 0000664 0000000 0000000 00000026725 14141214530 0024766 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: CanCan Integration
desc: Hook up GraphQL to CanCan abilities
index: 4
pro: true
---
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [CanCan](https://github.com/CanCanCommunity/cancancan).
__Why bother?__ You _could_ put your authorization code in your GraphQL types themselves, but writing a separate authorization layer gives you a few advantages:
- Since the authorization code isn't embedded in GraphQL, you can use the same logic in non-GraphQL (or legacy) parts of the app.
- The authorization logic can be tested in isolation, so your end-to-end GraphQL tests don't have to cover as many possibilities.
## Getting Started
__NOTE__: Requires the latest gems, so make sure your `Gemfile` has:
```ruby
# For CanCanIntegration:
gem "graphql-pro", ">=1.7.11"
# For list scoping:
gem "graphql", ">=1.8.7"
```
Then, `bundle install`.
Whenever you run queries, include `:current_user` in the context:
```ruby
context = {
current_user: current_user,
# ...
}
MySchema.execute(..., context: context)
```
And read on about the different features of the integration:
- [Authorizing Objects](#authorizing-objects)
- [Scoping Lists and Connections](#scopes)
- [Authorizing Fields](#authorizing-fields)
- [Authorizing Arguments](#authorizing-arguments)
- [Authorizing Mutations](#authorizing-mutations)
- [Custom Abilities Class](#custom-abilities-class)
## Authorizing Objects
For each object type, you can assign a required action for Ruby objects of that type. To get started, include the `ObjectIntegration` in your base object class:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
# Add the CanCan integration:
include GraphQL::Pro::CanCanIntegration::ObjectIntegration
# By default, require `can :read, ...`
can_can_action(:read)
# Or, to require no permissions by default:
# can_can_action(nil)
end
```
Now, anyone fetching an object will need `can :read, ...` for that object.
CanCan configurations are inherited, and can be overridden in subclasses. For example, to allow _all_ viewers to see the `Query` root type:
```ruby
class Types::Query < Types::BaseObject
# Allow anyone to see the query root
can_can_action nil
end
```
### Bypassing CanCan
`can_can_action(nil)` will override any inherited configuration and skip CanCan checks for an object, field, argument or mutation.
### 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" %}.
## 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" %}
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:
```ruby
class BaseUnion < GraphQL::Schema::Union
include GraphQL::Pro::CanCanIntegration::UnionIntegration
# To provide a default action for scoping lists:
can_can_action :read
end
module BaseInterface
include GraphQL::Schema::Interface
include GraphQL::Pro::CanCanIntegration::InterfaceIntegration
# To provide a default action for scoping lists:
can_can_action :read
end
```
#### Array
For Arrays, the CanCan integration will use `.select { ... }` to filter items using the `can_can_action` from the lists's type.
#### Bypassing scopes
To allow an unscoped relation to be returned from a field, disable scoping with `scope: false`, for example:
```ruby
# Allow anyone to browse the job postings
field :job_postings, [Types::JobPosting], null: false,
scope: false
```
## Authorizing Fields
You can also require certain checks on a field-by-field basis. First, include the integration in your base field class:
```ruby
# app/graphql/types/base_field.rb
class Types::BaseField < GraphQL::Schema::Field
# Add the CanCan integration:
include GraphQL::Pro::CanCanIntegration::FieldIntegration
# By default, don't require a role at field-level:
can_can_action nil
end
```
If you haven't already done so, you should also hook up your base field class to your base object and base interface:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
field_class Types::BaseField
end
# app/graphql/types/base_interface.rb
module Types::BaseInterface
# ...
field_class Types::BaseField
end
# app/graphql/mutations/base_mutation.rb
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field_class Types::BaseField
end
```
Then, you can add `can_can_action:` options to your fields:
```ruby
class Types::JobPosting < Types::BaseObject
# Only allow `can :review_applications, JobPosting` users
# to see who has applied
field :applicants, [Types::User], null: true,
can_can_action: :review_applicants
end
```
It will require the named action (`:review_applicants`) for the object being viewed (a `JobPosting`).
### Authorizing by attribute
CanCan 3.0 added attribute-level authorization ([pull request](https://github.com/CanCanCommunity/cancancan/pull/474)). You can leverage this in your field definitions with the `can_can_attribute:` configuration:
```ruby
# This will call `.can?(:read, user, :email_address)`
field :email_address, String, null: true,
can_can_action: :read,
can_can_attribute: :email_address
```
You could also provide a _default value_ for `can_can_attribute` in your base field class:
```ruby
class Types::BaseField
def initialize(*args, **kwargs, &block)
# pass all configs to the super class:
super
# Then set a new `can_can_attribute` value, if applicable
if can_can_attribute.nil? && can_can_action.present?
# `method_sym` is the thing GraphQL-Ruby will use to resolve this field
can_can_attribute(method_sym)
end
end
end
```
(See {{ "GraphQL::Schema::Field" | api_doc }} for the different values available for defaults.)
## Authorizing Arguments
Similar to field-level checks, you can require certain permissions to _use_ certain arguments. To do this, add the integration to your base argument class:
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
# Include the integration and default to no permissions required
include GraphQL::Pro::CanCanIntegration::ArgumentIntegration
can_can_action nil
end
```
Then, make sure your base argument is hooked up to your base field and base input object:
```ruby
class Types::BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
# PS: see "Authorizing Fields" to make sure your base field is hooked up to objects, interfaces and mutations
end
class Types::BaseInputObject < GraphQL::Schema::InputObject
argument_class Types::BaseArgument
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
end
```
Now, arguments accept a `can_can_action:` option, for example:
```ruby
class Types::Company < Types::BaseObject
field :employees, Types::Employee.connection_type, null: true do
# Only admins can filter employees by email:
argument :email, String, required: false, can_can_action: :admin
end
end
```
This will check for `can :admin, Company` (or a similar rule for the `company` being queried) for the current user.
## Authorizing Mutations
There are a few ways to authorize GraphQL mutations with the CanCan integration:
- Add a [mutation-level roles](#mutation-level-roles)
- Run checks on [objects loaded by ID](#authorizing-loaded-objects)
Also, you can configure [unauthorized object handling](#unauthorized-mutations)
#### Setup
Add `MutationIntegration` to your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include GraphQL::Pro::CanCanIntegration::MutationIntegration
# Also, to use argument-level authorization:
argument_class Types::BaseArgument
end
```
Also, you'll probably want a `BaseMutationPayload` where you can set a default role:
```ruby
class Types::BaseMutationPayload < Types::BaseObject
# If `BaseObject` requires some permissions, override that for mutation results.
# Assume that anyone who can run a mutation can read their generated result types.
can_can_action nil
end
```
And hook it up to your base mutation:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
object_class Types::BaseMutationPayload
field_class Types::BaseField
end
```
#### Mutation-level roles
Each mutation can have a class-level `can_can_action` which will be checked before loading objects or resolving, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
can_can_action :run_mutation
end
```
In the example above, `can :run_mutation, Mutations::PromoteEmployee` will be checked before running the mutation. (The currently-running instance of `Mutations::PromoteEmployee` is passed to the ability checker.)
#### Authorizing Loaded Objects
Mutations can automatically load and authorize objects by ID using the `loads:` option.
Beyond the normal [object reading permissions](#authorizing-objects), you can add an additional role for the specific mutation input using a `can_can_action:` option:
```ruby
class Mutations::FireEmployee < Mutations::BaseMutation
argument :employee_id, ID, required: true,
loads: Types::Employee,
can_can_action: :supervise,
end
```
In the case above, the mutation will halt unless the `can :supervise, ...` check returns true. (The fetched instance of `Employee` is passed to the ability checker.)
#### Unauthorized Mutations
By default, an authorization failure in a mutation will raise a Ruby exception. You can customize this by implementing `#unauthorized_by_can_can(owner, value)` in your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def unauthorized_by_can_can(owner, value)
# No error, just return nil:
nil
end
end
```
The method is called with:
- `owner`: the `GraphQL::Schema::Argument` instance or mutation class whose role was not satisfied
- `value`: the object which didn't pass for `context[:current_user]`
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" %}:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field :errors, [String], null: true
def unauthorized_by_can_can(owner, value)
# Return errors as data:
{ errors: ["Missing required permission: #{owner.can_can_action}, can't access #{value.inspect}"] }
end
end
```
## Custom Abilities Class
By default, the integration will look for a top-level `::Ability` class.
If you're using a different class, provide an instance ahead-of-time as `context[:can_can_ability]`
For example, you could _always_ add one in your schema's `#execute` method:
```ruby
class MySchema < GraphQL::Schema
# Override `execute` to provide a custom Abilities instance for the CanCan integration
def self.execute(*args, context: {}, **kwargs)
# Assign `context[:can_can_ability]` to an instance of our custom class
context[:can_can_ability] = MyAuthorization::CustomAbilitiesClass.new(context[:current_user])
super
end
end
```
graphql-ruby-1.11.10/guides/authorization/overview.md 0000664 0000000 0000000 00000014131 14141214530 0022633 0 ustar 00root root 0000000 0000000 ---
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
---
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.
## Authorization: GraphQL vs REST
In a REST API, the common authorization pattern is fairly simple. Before performing the requested action, the server asserts that the current client has the required permissions for that action. For example:
```ruby
class PostsController < ApiController
def create
# First, check the client's permission level:
if current_user.can?(:create_posts)
# If the user is permitted, then perform the action:
post = Post.create(params)
render json: post
else
# Otherwise, return an error:
render nothing: true, status: 403
end
end
end
```
However, this request-by-request mindset doesn't map well to GraphQL because there's only one controller and the requests that come to it may be _very_ different. To illustrate the problem:
```ruby
class GraphqlController < ApplicationController
def execute
# What permission is required for `query_str`?
# It depends on the string! So, you can't generalize at this level.
if current_user.can?(:"???")
MySchema.execute(query_str, context: ctx, variables: variables)
end
end
end
```
So, what new mindset will work with a GraphQL API?
For __mutations__, remember that each mutation is like an API request in itself. For example, `Posts#create` above would map to the `createPost(...)` mutation in GraphQL. So, each mutation should be authorized in its own right.
For __queries__, you can think of each individual _object_ like a `GET` request to a REST API. So, each object should be authorized for reading in its own right.
By applying this mindset, each part of the GraphQL query will be properly authorized before it is executed. Also, since the different units of code are each authorized on their own, you can be sure that each incoming query will be properly authorized, even if it's a brand new query that the server has never seen before.
## What About Authentication?
As a reminder:
- _Authentication_ is the process of determining what user is making the current request, for example, accepting a username and password, or finding a `User` in the database from `session[:current_user_id]`.
- _Authorization_ is the process of verifying that the current user has permission to do something (or see something), for example, checking `admin?` status or looking up permission groups from the database.
In general, authentication is _not_ addressed in GraphQL at all. Instead, your controller should get the current user based on the HTTP request (eg, an HTTP header or a cookie) and provide that information to the GraphQL query. For example:
```ruby
class GraphqlController < ApplicationController
def execute
# Somehow get the current `User` from this HTTP request.
current_user = get_logged_in_user(request)
# Provide the current user in `context` for use during the query
context = { current_user: current_user }
MySchema.execute(query_str, context: context, ...)
end
end
```
After your HTTP handler has loaded the current user, you can access it via `context[:current_user]` in your GraphQL code.
## Authorization in Your Business Logic
Before introducing GraphQL-specific authorization, consider the advantages of application-level authorization. (See the [GraphQL.org post](https://graphql.org/learn/authorization/) on the same topic.) For example, here's authorization mixed into the GraphQL API layer:
```ruby
field :posts, [Types::Post], null: false
def posts
# Perform an auth check in the GraphQL field code:
if context[:current_user].admin?
Post.all
else
Post.published
end
end
```
The downside of this is that, when `Types::Post` is queried in other contexts, the same authorization check may not be applied. Additionally, since the authorization code is coupled with the GraphQL API, the only way to test it is via GraphQL queries, which adds some complexity to tests.
Alternatively, you could move the authorization to your business logic, the `Post` class:
```ruby
class Post < ActiveRecord::Base
# Return the list of posts which `user` may see
def self.posts_for(user)
if user.admin?
self.all
else
self.published
end
end
end
```
Then, use this application method in your GraphQL code:
```ruby
field :posts, [Types::Post], null: false
def posts
# Fetch the posts this user can see:
Post.posts_for(context[:current_user])
end
```
In this case, `Post.posts_for(user)` could be tested _independently_ from GraphQL. Then, you have less to worry about in your GraphQL tests. As a bonus, you can use `Post.posts_for(user)` in _other_ parts of the app, too, such as the web UI or REST API.
## GraphQL-Ruby's Authorization Framework
Despite the advantages of authorization at the application layer, as described above, there might be some reasons to authorize in the API layer:
- Have an extra assurance that your API layer is secure
- Authorize the API request _before_ running it (see "visibility" below)
- Integrate with code that doesn't have authorization built-in
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 "Accessibility", "/authorization/accessibility" %} prevents running queries which access parts of the GraphQL schema, unless users have the required permission.
- {% internal_link "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" %}.
graphql-ruby-1.11.10/guides/authorization/pundit_integration.md 0000664 0000000 0000000 00000037525 14141214530 0024707 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Pundit Integration
desc: Hook up GraphQL to Pundit policies
index: 4
pro: true
---
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [Pundit](https://github.com/varvet/pundit) policies.
__Why bother?__ You _could_ put your authorization code in your GraphQL types themselves, but writing a separate authorization layer gives you a few advantages:
- Since the authorization code isn't embedded in GraphQL, you can use the same logic in non-GraphQL (or legacy) parts of the app.
- The authorization logic can be tested in isolation, so your end-to-end GraphQL tests don't have to cover as many possibilities.
## Getting Started
__NOTE__: Requires the latest gems, so make sure your `Gemfile` has:
```ruby
# For PunditIntegration:
gem "graphql-pro", ">=1.7.9"
# For list scoping:
gem "graphql", ">=1.8.7"
```
Then, `bundle install`.
Whenever you run queries, include `:current_user` in the context:
```ruby
context = {
current_user: current_user,
# ...
}
MySchema.execute(..., context: context)
```
And read on about the different features of the integration:
- [Authorizing Objects](#authorizing-objects)
- [Scoping Lists and Connections](#scopes)
- [Authorizing Fields](#authorizing-fields)
- [Authorizing Arguments](#authorizing-arguments)
- [Authorizing Mutations](#authorizing-mutations)
- [Custom Policy Lookup](#custom-policy-lookup)
- [Custom User Lookup](#custom-user-lookup)
## Authorizing Objects
You can specify Pundit roles that must be satisfied in order for viewers to see objects of a certain type. To get started, include the `ObjectIntegration` in your base object class:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
# Add the Pundit integration:
include GraphQL::Pro::PunditIntegration::ObjectIntegration
# By default, require staff:
pundit_role :staff
# Or, to require no permissions by default:
# pundit_role nil
end
```
Now, anyone trying to read a GraphQL object will have to pass the `#staff?` check on that object's policy.
Then, each child class can override that parent configuration. For example, allow _all_ viewers to read the `Query` root:
```ruby
class Types::Query < Types::BaseObject
# Allow anyone to see the query root
pundit_role nil
end
```
#### Policies and Methods
For each object returned by GraphQL, the integration matches it to a policy and method.
The policy is found using [`Pundit.policy!`](https://www.rubydoc.info/gems/pundit/Pundit%2Epolicy!), which looks up a policy using the object's class name. (This can be customized, see below.)
Then, GraphQL will call a method on the policy to see whether the object is permitted or not. This method is assigned in the object class, for example:
```ruby
class Types::Employee < Types::BaseObject
# Only show employee objects to their bosses,
# or when that employee is the current viewer
pundit_role :employer_or_self
# ...
end
```
That configuration will call `#employer_or_self?` on the corresponding Pundit policy.
#### Custom Policy Class
By default, the integration uses `Pundit.policy!(current_user, object)` to find a policy. You can specify a policy class using `pundit_policy_class(...)`:
```ruby
class Types::Employee < Types::BaseObject
pundit_policy_class(Policies::CustomEmployeePolicy)
# Or, you could use a string:
# pundit_policy_class("Policies::CustomEmployeePolicy")
end
```
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
#### Bypassing Policies
The integration requires that every object with a `pundit_role` has a corresponding policy class. To allow objects to _skip_ authorization, you can pass `nil` as the role:
```ruby
class Types::PublicProfile < Types::BaseObject
# Anyone can see this
pundit_role nil
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" %}.
## 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.
To scope lists of interface or union type, include the integration in your base union class and base interface module:
```ruby
class BaseUnion < GraphQL::Schema::Union
include GraphQL::Pro::PunditIntegration::UnionIntegration
end
module BaseInterface
include GraphQL::Schema::Interface
include GraphQL::Pro::PunditIntegration::InterfaceIntegration
end
```
Pundit scopes [don't play well](https://github.com/rmosolgo/graphql-ruby/issues/2008) with `Array`s, so the integration _skips_ scopes on Arrays. You can also opt out on a field-by-field basis as described below.
You can also customize how the scopes are looked up and applied, see below.
#### Bypassing scopes
To allow an unscoped relation to be returned from a field, disable scoping with `scope: false`, for example:
```ruby
# Allow anyone to browse the job postings
field :job_postings, [Types::JobPosting], null: false,
scope: false
```
## Authorizing Fields
You can also require certain checks on a field-by-field basis. First, include the integration in your base field class:
```ruby
# app/graphql/types/base_field.rb
class Types::BaseField < GraphQL::Schema::Field
# Add the Pundit integration:
include GraphQL::Pro::PunditIntegration::FieldIntegration
# By default, don't require a role at field-level:
pundit_role nil
end
```
If you haven't already done so, you should also hook up your base field class to your base object and base interface:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
field_class Types::BaseField
end
# app/graphql/types/base_interface.rb
module Types::BaseInterface
# ...
field_class Types::BaseField
end
# app/graphql/mutations/base_mutation.rb
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field_class Types::BaseField
end
```
Then, you can add `pundit_role:` options to your fields:
```ruby
class Types::JobPosting < Types::BaseObject
# Allow signed-in users to browse listings
pundit_role :signed_in
# But, only allow `JobPostingPolicy#staff?` users to see
# who has applied
field :applicants, [Types::User], null: true,
pundit_role: :staff
end
```
It will call the named role (eg, `#staff?`) on the parent object's policy (eg `JobPostingPolicy`).
#### Custom Policy Class
You can override the policy class for a field using `pundit_policy_class:`, for example:
```ruby
class Types::JobPosting < Types::BaseObject
# Only allow `ApplicantsPolicy#staff?` users to see
# who has applied
field :applicants, [Types::User], null: true,
pundit_role: :staff,
pundit_policy_class: ApplicantsPolicy
# Or with a string:
# pundit_policy_class: "ApplicantsPolicy"
end
```
This will initialize an `ApplicantsPolicy` with the parent object (a `Job`) and call `#staff?` on it.
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
## Authorizing Arguments
Similar to field-level checks, you can require certain permissions to _use_ certain arguments. To do this, add the integration to your base argument class:
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
# Include the integration and default to no permissions required
include GraphQL::Pro::PunditIntegration::ArgumentIntegration
pundit_role nil
end
```
Then, make sure your base argument is hooked up to your base field and base input object:
```ruby
class Types::BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
# PS: see "Authorizing Fields" to make sure your base field is hooked up to objects, interfaces and mutations
end
class Types::BaseInputObject < GraphQL::Schema::InputObject
argument_class Types::BaseArgument
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
end
```
Now, arguments accept a `pundit_role:` option, for example:
```ruby
class Types::Company < Types::BaseObject
field :employees, Types::Employee.connection_type, null: true do
# Only admins can filter employees by email:
argument :email, String, required: false, pundit_role: :admin
end
end
```
The role will be called on the parent object's policy, for example `CompanyPolicy#admin?` in the case above.
## Authorizing Mutations
There are a few ways to authorize GraphQL mutations with the Pundit integration:
- Add a [mutation-level roles](#mutation-level-roles)
- Run checks on [objects loaded by ID](#authorizing-loaded-objects)
Also, you can configure [unauthorized object handling](#unauthorized-mutations)
#### Setup
Add `MutationIntegration` to your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include GraphQL::Pro::PunditIntegration::MutationIntegration
# Also, to use argument-level authorization:
argument_class Types::BaseArgument
end
```
Also, you'll probably want a `BaseMutationPayload` where you can set a default role:
```ruby
class Types::BaseMutationPayload < Types::BaseObject
# If `BaseObject` requires some permissions, override that for mutation results.
# Assume that anyone who can run a mutation can read their generated result types.
pundit_role nil
end
```
And hook it up to your base mutation:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
object_class Types::BaseMutationPayload
field_class Types::BaseField
end
```
#### Mutation-level roles
Each mutation can have a class-level `pundit_role` which will be checked before loading objects or resolving, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
pundit_role :admin
end
```
In the example above, `PromoteEmployeePolicy#admin?` will be checked before running the mutation.
#### Custom Policy Class
By default, Pundit uses the mutation's class name to look up a policy. You can override this by defining `pundit_policy_class` on your mutation:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
pundit_policy_class ::UserPolicy
pundit_role :admin
end
```
Now, the mutation will check `UserPolicy#admin?` before running.
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
#### Authorizing Loaded Objects
Mutations can automatically load and authorize objects by ID using the `loads:` option.
Beyond the normal [object reading permissions](#authorizing-objects), you can add an additional role for the specific mutation input using a `pundit_role:` option:
```ruby
class Mutations::FireEmployee < Mutations::BaseMutation
argument :employee_id, ID, required: true,
loads: Types::Employee,
pundit_role: :supervisor,
end
```
In the case above, the mutation will halt unless the `EmployeePolicy#supervisor?` method returns true.
#### Unauthorized Mutations
By default, an authorization failure in a mutation will raise a Ruby exception. You can customize this by implementing `#unauthorized_by_pundit(owner, value)` in your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def unauthorized_by_pundit(owner, value)
# No error, just return nil:
nil
end
end
```
The method is called with:
- `owner`: the `GraphQL::Schema::Argument` or mutation class whose role was not satisfied
- `value`: the object which didn't pass for `context[:current_user]`
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" %}:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field :errors, [String], null: true
def unauthorized_by_pundit(owner, value)
# Return errors as data:
{ errors: ["Missing required permission: #{owner.pundit_role}, can't access #{value.inspect}"] }
end
end
```
## Custom Policy Lookup
By default, the integration uses `Pundit`'s top-level methods to interact with policies:
- `Pundit.policy!(context[:current_user], object)` is called to find a policy instance
- `Pundit.policy_scope!(context[:current_user], items)` is called to filter `items`
### Custom Policy Methods
You can implement a custom lookup by defining the following methods in your schema:
- `pundit_policy_class_for(object, context)` to return a policy class (or raise an error if one isn't found)
- `pundit_role_for(object, context)` to return a role method (Symbol), or `nil` to bypass authorization
- `scope_by_pundit_policy(context, items)` to apply a scope to `items` (or raise an error if one isn't found)
Since different objects have different lifecycles, the hooks are installed slightly different ways:
- Your base argument, field, and mutation classes should have _instance methods_ with those names
- Your base type classes should have _class methods_ with that name
Here's an example of how the custom hooks can be installed:
```ruby
module CustomPolicyLookup
# Lookup policies in the `SystemAdmin::` namespace for system_admin users
def pundit_policy_class_for(object, context)
current_user = context[:current_user]
if current_user.system_admin?
policy_class = SystemAdmin.const_get("#{object.class.name}Policy")
policy_class.new(current_user, object)
else
super
end
end
# Require admin permissions if the object is pending_approval
def pundit_role_for(object, context)
if object.pending_approval?
:admin
else
super # fall back to the normally-configured role
end
end
end
# Add policy hooks as class methods
class Types::BaseObject < GraphQL::Schema::Object
extend CustomPolicyLookup
end
class Types::BaseUnion < GraphQL::Schema::Union
extend CustomPolicyLookup
end
module Types::BaseInterface
include GraphQL::Schema::Interface
# Add this as a class method that will be "inherited" by other interfaces:
definition_methods do
include CustomPolicyLookup
end
end
# Add policy hooks as instance methods
class Types::BaseField < GraphQL::Schema::Field
include CustomPolicyLookup
end
class Types::BaseArgument < GraphQL::Schema::Argument
include CustomPolicyLookup
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include CustomPolicyLookup
end
```
### One Policy Per Class
Another good approach is to have one policy per class. You can implement `policy_class_for(object, context)` to look up a policy _within_ the class, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def policy_class_for(_object, _context)
# Look up a nested `Policy` constant:
self.class.const_get(:Policy)
end
end
```
Then, each mutation can define its policy inline, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
# This will be found by `BaseMutation.policy_class`, defined above:
class Policy
# ...
end
pundit_role :admin
end
```
Now, `Mutations::PromoteEmployee::Policy#admin?` will be checked before running the mutation.
## Custom User Lookup
By default, the Pundit integration looks for the current user in `context[:current_user]`. You can override this by implementing `#pundit_user` on your custom query context class. For example:
```ruby
# app/graphql/query_context.rb
class QueryContext < GraphQL::Query::Context
def pundit_user
# Lookup `context[:viewer]` instead:
self[:viewer]
end
end
```
Then be sure to hook up your custom class in the schema:
```ruby
class MySchema < GraphQL::Schema
context_class(QueryContext)
end
```
Then, the Pundit integration will use your `def pundit_user` to get the current user at runtime.
graphql-ruby-1.11.10/guides/authorization/scoping.md 0000664 0000000 0000000 00000003021 14141214530 0022423 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Scoping
desc: Filter lists to match the current viewer and context
index: 4
---
_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. The resulting subset is authorized as normal, and, assuming that it was properly scoped, each item should pass authorization checks.
For similar features, see [Pundit scopes](https://github.com/varvet/pundit#scopes) and [Cancan's `.accessible_by`](https://github.com/cancancommunity/cancancan/wiki/Fetching-Records).
## `scope:` option
Fields accept a `scope:` option to enable (or disable) scoping, for example:
```ruby
field :products, [Types::Product], scope: true
# Or
field :all_products, [Types::Product], scope: false
```
For __list__ and __connection__ fields, `scope: true` is the default. For all other fields, `scope: false` is the default. You can override this by using the `scope:` option.
## `.scope_items(items, ctx)` method
Type classes may implement `.scope_items(items, ctx)`. This method is called when a field has `scope: true`. For example,
```ruby
field :products, [Types::Product] # has `scope: true` by default
```
Will call:
```ruby
class Types::Product < Types::BaseObject
def self.scope_items(items, context)
# filter items here
end
end
```
The method should return a new list with only the appropriate items for the current `context`.
graphql-ruby-1.11.10/guides/authorization/visibility.md 0000664 0000000 0000000 00000004423 14141214530 0023157 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Visibility
desc: Programatically hide parts of the GraphQL schema from some users.
index: 1
---
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.
Here are some reasons you might want to hide parts of your schema:
- You don't want non-admin users to know about administration functions of the schema.
- You're developing a new feature and want to make a gradual release to only a few users first.
## Hiding Parts of the Schema
You can customize the visibility of parts of your schema by reimplementing various `visible?` methods:
- Type classes have a `.visible?(context)` class method
- Fields and arguments have a `#visible?(context)` instance method
- Enum values have `#visible?(context)` instance method
- Mutation classes have a `.visible?(context)` class method
These methods are called with the query context, based on the hash you pass as `context:`. If the method returns false, then that member of the schema will be treated as though it doesn't exist for the entirety of the query. That is:
- In introspection, the member will _not_ be included in the result
- In normal queries, if a query references that member, it will return a validation error, since that member doesn't exist
## For Example
Let's say you're working on a new feature which should remain secret for a while. You can implement `.visible?` in a type:
```ruby
class Types::SecretFeature < Types::BaseObject
def self.visible?(context)
# only show it to users with the secret_feature enabled
super && context[:viewer].feature_enabled?(:secret_feature)
end
end
```
(Always call `super` to inherit the default behavior.)
Now, the following bits of GraphQL will return validation errors:
- Fields that return `SecretFeature`, eg `query { findSecretFeature { ... } }`
- Fragments on `SecretFeature`, eg `Fragment SF on SecretFeature`
And in introspection:
- `__schema { types { ... } }` will not include `SecretFeature`
- `__type(name: "SecretFeature")` will return `nil`
- Any interfaces or unions which normally include `SecretFeature` will _not_ include it
- Any fields that return `SecretFeature` will be excluded from introspection
graphql-ruby-1.11.10/guides/css/ 0000775 0000000 0000000 00000000000 14141214530 0016333 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/css/main.scss 0000664 0000000 0000000 00000025102 14141214530 0020154 0 ustar 00root root 0000000 0000000 ---
---
@import "reset";
$brand-color: #a5152a;
$brand-color-light: #ed8090;
$brand-color-extralight: #f9e8ee;
$experimental-background: #fff7cf;
$experimental-color: #655400;
$class-based-background: #c1f6ff;
$class-based-color: #003a58;
$pro-color: #406db5;
$pro-background: #f1f4f9;
$faint-color: #f0f0f0;
$code-border: #d6d6d6;
$code-background: #fafafa;
$code-color: #777777;
$code-border-radius: 2px;
$muted-color: #777777;
$subtle-color: #aaaaaa;
$font: 'Rubik', sans-serif;
$font-color: black;
$code-font: 'Monaco', monospace;
body {
font-family: $font;
background: #fafafa;
}
strong, b {
font-weight: bold;
}
// Algolia highlights:
.ais-Highlight {
font-style: normal;
font-weight: bold;
}
.header {
box-shadow: 0px 0px 10px 0px #d6d6d6;
z-index: 1;
position: relative;
background: white;
.nav {
$height: 30px;
$margin: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
$fade-time: 0.2s;
.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;
padding: $margin;
height: $height;
display: flex;
align-items: center;
text-decoration: none;
}
}
}
.header-container {
max-width: 1040px;
margin: 0px auto;
}
.container {
max-width: 1000px;
margin: 0px auto;
padding: 10px 20px;
background: white;
}
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;
}
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;
}
code {
font-family: $code-font;
color: $code-color;
font-weight: 400;
}
.code .line-numbers {
display: none;
}
a {
color: $brand-color;
border-color: $brand-color;
}
a:hover, a:hover code {
color: white;
background-color: $brand-color;
}
#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;
}
.monitoring-img-group {
display: flex;
flex-direction: row;
margin-bottom: 20px;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.guides-toc {
ul {
list-style: none;
display: flex;
flex-wrap: wrap;
}
li {
padding-bottom: 10px;
padding-right: 10px;
}
}
.breadcrumb {
color: $muted-color;
}
.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;
&:hover {
background-color: $color;
color: $background-color;
}
}
}
.experimental-header {
@include doc-header($experimental-color, $experimental-background);
}
.class-based-header {
@include doc-header($class-based-color, $class-based-background);
}
.pro-header {
@include doc-header($pro-color, $pro-background);
}
.guide-footer {
background: $brand-color-extralight;
margin: 25px 0px 0px 0px;
padding: 10px;
border-radius: $code-border-radius;
}
.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-part {
padding: 10px;
&.shaded {
background: $faint-color;
}
h2 {
color: $brand-color;
text-shadow: #cccccc 1px 1px 1px;
font-size: 1.4em;
}
}
.hero-feature {
display: flex;
flex-basis: 50%;
flex-grow: 0;
flex-shrink: 0;
justify-content: space-between;
.teaser p {
font-size: 1.2em;
line-height: 2em;
}
.teaser:first-child {
margin-right: 10px;
}
.teaser:last-child {
margin-left: 10px;
}
}
}
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;
}
}
li p, li div {
display: inline-block;
}
.search-input {
font-size: 1em;
padding: 5px;
margin: 10px;
border: 1px solid $subtle-color;
border-radius: 3px;
// make it float right in a flex container
margin-left: auto;
}
.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;
.search-title {
color: $brand-color;
}
background-color: $bg-highlight;
}
&:hover {
border-bottom-color: $brand-color;
}
}
}
}
/* 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 */
graphql-ruby-1.11.10/guides/defer/ 0000775 0000000 0000000 00000000000 14141214530 0016630 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/defer/overview.md 0000664 0000000 0000000 00000004413 14141214530 0021022 0 ustar 00root root 0000000 0000000 ---
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.
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).
`@defer` requires the new {% internal_link "interpreter runtime", "/queries/interpreter" %} which ships with GraphQL-Ruby 1.9+.
## Example
GraphQL queries can be large and complex, requiring lots of computation or dependencies on slow external services.
In this example, the local server maintains an index of items ("decks"), but the item data ("cards") is actually hosted on a remote server. So, GraphQL queries must make remote calls in order to serve that data.
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:
```diff
deck {
slots {
quantity
- card
+ card @defer {
name
price
}
}
}
```
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.
View the full demo at https://github.com/rmosolgo/graphql_defer_example.
## Considerations
- `@defer` adds some overhead to the response, so only apply it judiciously.
- `@defer` is single-threaded. `@defer`ed fields are still evaluated in sequence, but in a chunk-by-chunk way.
## Next Steps
{% internal_link "Set up your server", "/defer/setup" %} to support `@defer` or read about {% internal_link "client usage", "/defer/usage" %} of it.
graphql-ruby-1.11.10/guides/defer/setup.md 0000664 0000000 0000000 00000010032 14141214530 0020306 0 ustar 00root root 0000000 0000000 ---
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
---
Before using `@defer` in queries, you have to:
- Update `graphql` and `graphql-pro` gems
- Add `@defer` to your GraphQL schema
- Update your HTTP handlers (eg, Rails controllers) to send streaming responses
You can also see a [full Rails & Apollo-Client demo](https://github.com/rmosolgo/graphql_defer_example).
## Updating the gems
`GraphQL::Pro::Defer` is included in `graphql-pro 1.10+`, and it requires the new {% internal_link "Interpreter runtime", "/queries/interpreter" %} in `graphql 1.9+`, so update your gemfile:
```ruby
# 1.9+ for Interpreter
gem "graphql", "~>1.9.0"
# 1.10+ for `@defer`
gem "graphql-pro", "~>1.10.0"
```
And then install them:
```
$ bundle update graphql graphql-pro
```
## Adding `@defer` to your schema
Then, add `GraphQL::Pro::Defer` to your schema as a plugin:
```ruby
class MySchema < GraphQL::Schema
# The new interpreter runtime (1.9+) is required:
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
# Then add the directive:
use GraphQL::Pro::Defer
end
```
This will:
- Attach a {% internal_link "custom directive", "/type_definitions/directives" %} called `@defer`
- Add instrumentation to queries to track deferred work and execute it later
## Sending streaming responses
Many web frameworks have support for streaming responses, for example:
- Rails has [ActionController::Live](https://api.rubyonrails.org/classes/ActionController/Live.html)
- Sinatra has [Sinatra::Streaming](http://sinatrarb.com/contrib/streaming.html)
- Hanami::Controller can [stream responses](https://github.com/hanami/controller#streamed-responses)
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`.
### Checking for deferrals
When a query has any `@defer`ed fields, you can check for `context[:defer]`:
```ruby
if context[:defer]
# some fields were `@defer`ed
else
# normal GraphQL, no `@defer`
end
```
### Working with deferrals
To handle deferrals, you can enumerate over `context[:defer]`, for example:
```ruby
context[:defer].each do |deferral|
# do something with the `deferral`, eg
# stream_to_client(deferral.to_h)
end
```
The initial result is _also_ present in the deferrals, so you can treat it just like a patch.
Each deferred patch has a few methods for building a response:
- `.to_h` returns a hash with `path:`, `data:`, and/or `errors:`. (There is no `path:` for the root result.)
- `.to_http_multipart` returns a string which works with Apollo client's `@defer` support.
- `.path` returns the path to this patch in the response
- `.data` returns successfully-resolved results of the patch
- `.errors` returns an array of errors, if there were any
Calling `.data` or `.errors` on a deferral will resume GraphQL execution until the patch is complete.
### Example: Rails with Apollo Client
In this example, a Rails controller will stream HTTP Multipart patches to the client, in Apollo Client's supported format.
```ruby
class GraphqlController < ApplicationController
# Support `response.stream` below:
include ActionController::Live
def execute
# ...
result = MySchema.execute(query, variables: variables, context: context, operation_name: operation_name)
# Check if this is a deferred query:
if (deferred = result.context[:defer])
# Use built-in `stream_http_multipart` with Apollo-Client & ActionController::Live
deferred.stream_http_multipart(response)
else
# Return a plain, non-deferred result
render json: result
end
ensure
# Always make sure to close the stream
response.stream.close
end
end
```
You can also investigate a [full Rails & Apollo-Client demo](https://github.com/rmosolgo/graphql_defer_example)
## Next Steps
Read about {% internal_link "client usage", "/defer/usage" %} of `@defer`.
graphql-ruby-1.11.10/guides/defer/usage.md 0000664 0000000 0000000 00000002253 14141214530 0020260 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: GraphQL Pro - Defer
title: Usage
desc: Using @defer on the client side
index: 2
pro: true
---
`@defer` is a [GraphQL directive](https://graphql.org/learn/queries/#directives) which instructs the server to execute the field in a special way:
```graphql
query GetPlayerInfo($handle: String!){
player(handle: $handle) {
name
# Send this field later, to avoid slowing down the initial response:
topScore(from: 2000, to: 2020) @defer
}
}
```
The directives `@skip` and `@include` are built into any GraphQL server and client, but `@defer` requires special attention.
Apollo-Client has [experimental support](https://www.apollographql.com/docs/react/features/defer-support.html)
but it may [have some issues](https://github.com/apollographql/apollo-client/issues/4484), so you can try [this updated fork](https://github.com/rmosolgo/apollo-client) while they're worked out.
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!
## Next Steps
{% internal_link "Set up your server", "/defer/setup" %} to support `@defer`.
graphql-ruby-1.11.10/guides/development.md 0000664 0000000 0000000 00000024264 14141214530 0020417 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
title: Development
section: Other
desc: Hacking on GraphQL Ruby
---
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
- Special tools for building the [lexer and parser](#lexer-and-parser)
- Building and publishing the [GraphQL Ruby website](#website)
- [Versioning](#versioning) describes how changes are managed and released
- [Releasing](#releasing) Gem versions
### Setup
Get your own copy of graphql-ruby by forking [`rmosolgo/graphql-ruby` on GitHub](https://github.com/rmosolgo/graphql-ruby) and cloning your fork.
Then, install the dependencies:
- Install SQLite3 and MongoDB (eg, `brew install sqlite && brew tap mongodb/brew && brew install mongodb-community`)
- `bundle install`
- Optional: [Ragel](https://www.colm.net/open-source/ragel/) is required to build the lexer
### Running the Tests
#### Unit tests
You can run the tests with
```
bundle exec rake # tests & Rubocop
bundle exec rake test # tests only
```
You can run a __specific file__ with `TEST=`:
```
bundle exec rake test TEST=spec/graphql/query_spec.rb
# run tests in `query_spec.rb` only
```
Alternatively, you can run a __specific file__ with the [m](https://github.com/qrush/m) gem:
```
m spec/graphql/query_spec.rb
# run tests in `query_spec.rb` only
```
You can focus on a __specific example__ with `focus`:
```ruby
focus
it "does something cool" do
# ...
end
```
Then, only `focus`ed tests will run:
```
bundle exec rake test
# only the focused test will be run
```
(This is provided by `minitest-focus`.)
You can __watch files__ with `guard`:
```
bundle exec guard
```
When a file in `lib/` is modified, `guard` will run the corresponding file in `spec`. Guard also respects `# test_via:` comments, so it will run that test when the file changes (if there is no corresponding file by name).
#### Integration tests
You need to pick a specific gemfile from gemfiles/ to run integration tests. For example:
```
BUNDLE_GEMFILE=gemfiles/rails_5.1.gemfile bundle install
BUNDLE_GEMFILE=gemfiles/rails_5.1.gemfile bundle exec rake test TEST=spec/integration/rails/graphql/relay/array_connection_spec.rb
```
#### Other tests
There are system tests for checking ActionCable behavior, use:
```
bundle exec rake test:system
```
And JavaScript tests:
```
bundle exec rake test:js
```
### Gemfiles, Gemfiles, Gemfiles
`graphql-ruby` has several gemfiles to ensure support for various Rails versions.
You can run all gemfiles with
```
appraisal rake
```
You can specify a gemfile with `BUNDLE_GEMFILE`, eg:
```
BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle exec rake
```
### Debugging with Pry
[`pry`](https://pryrepl.org/) is included with GraphQL-Ruby's development setup to help with debugging.
To pause execution in Ruby code, add:
```ruby
binding.pry
```
Then, the program will pause and your terminal will become a Ruby REPL. Feel free to use `pry` in your development process!
### Running the Benchmarks
This project includes some Rake tasks to record benchmarks:
```sh
$ bundle exec rake -T | grep bench:
rake bench:profile # Generate a profile of the introspection query
rake bench:query # Benchmark the introspection query
rake bench:validate # Benchmark validation of several queries
```
You can save results by sending the output into a file:
```sh
$ bundle exec rake bench:validate > before.txt
$ cat before.txt
# ...
# --> benchmark output here
```
If you want to check performance, create a baseline by running these tasks before your changes. Then, make your changes and run the tasks again and compare your results.
Keep these points in mind when using benchmarks:
- The results are hardware-specific: computers with different hardware will have different results. So don't compare your results to results from other computers.
- The results are environment-specific: CPU and memory availability are affected by other processes on your computer. So try to create similar environments for your before-and-after testing.
### Coding Guidelines
GraphQL-Ruby uses a thorough test suite to make sure things work reliably day-after-day. Please include tests that describe your changes, for example:
- If you contribute a bug fix, include a test for the code that _was_ broken (and is now fixed)
- If you contribute a feature, include tests for all intended uses of that feature
- If you modify existing behavior, update the tests to cover all intended behaviors for that code
Don't fret about coding style or organization. There's a minimal Rubocop config in `.rubocop.yml` which runs during CI. You can run it manually with `bundle exec rake rubocop`.
### Lexer and Parser
The lexer and parser use a multistep build process:
- Write the definition (`lexer.rl` or `parser.y`)
- Run the generator (Ragel or Racc) to create `.rb` files (`lexer.rb` or `parser.rb`)
- `require` those `.rb` files in GraphQL-Ruby
To update the lexer or parser, you should update their corresponding _definitions_ (`lexer.rl` or `parser.y`). Then, you can run `bundle exec rake build_parser` to re-generate the `.rb` files.
You will need Ragel to build the lexer (see above).
If you start __guard__ (`bundle exec guard`), the `.rb` files will be rebuilt whenever the definition files are modified.
#### Install Ragel and Colm on a Mac
GraphQL Ruby requires Ragel 7.0.0.9 which is not available on Homebrew. To install it, you might have to download it from source.
This is not meant to be a step by step guide and will likely not work as the documentation ages.
Download colm from [http://www.colm.net/files/colm/colm-0.13.0.4.tar.gz](http://www.colm.net/files/colm/colm-0.13.0.4.tar.gz)
Download ragel from [http://www.colm.net/files/ragel/ragel-7.0.0.9.tar.gz](http://www.colm.net/files/ragel/ragel-7.0.0.9.tar.gz)
```sh
# In colm directory
cat README # for install instructions
# The author who added this documentation succeeded with these steps
./configure
make
make install
# After installing colm, in ragel directory
./configure
make
make install
```
### Website
To update the website, update the `.md` files in `guides/`.
To preview your changes, you can serve the website locally:
```
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:
```
$ export ALGOLIA_API_KEY=...
```
Without this key, the search index will fall out-of-sync with the website. Contact @rmosolgo to gain access to this key.
#### 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:
```
$ bundle exec rake site:publish
```
Finally, check your work by visiting the docs on the website.
### Versioning
GraphQL-Ruby does _not_ attempt to deliver "semantic versioning" for the reasons described in `jashkenas`'
s post, ["Why Semantic Versioning Isn't"](https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e). Instead, the following scheme is used as a guideline:
- Version numbers consist of three parts, `MAJOR.MINOR.PATCH`
- __`PATCH`__ version indicates bug fixes or small features for specific use cases. Ideally, you can upgrade patch versions with only a quick skim of the changelog.
- __`MINOR`__ version indicates significant additions, internal refactors, or small breaking changes. When upgrading a minor version, check the changelog for any new features or breaking changes which apply to your system. The changelog will always include an upgrade path for any breaking changes. Minor versions may also include deprecation warnings to warn about upcoming breaking changes.
- __`MAJOR`__ version indicates significant breaking changes. Do not expect code to run without some modification, especially if the code yielded deprecation warnings.
This policy is inspired by the [Ruby 2.1.0+ version policy](https://www.ruby-lang.org/en/news/2013/12/21/ruby-version-policy-changes-with-2-1-0/).
Pull requests and issues may be tagged with a [GitHub milestone](https://github.com/rmosolgo/graphql-ruby/milestones) to denote when they'll be released.
The [changelog](https://github.com/rmosolgo/graphql-ruby/blob/master/CHANGELOG.md) should always contain accurate and thorough information so that users can upgrade. If you have trouble upgrading based on the changelog, please open an issue on GitHub.
### Releasing
GraphQL-Ruby doesn't have a strict release schedule. If you think it should, consider opening an issue to share your thoughts.
To cut a release:
- Update `CHANGELOG.md` for the new version:
- Add a new heading for the new version, and paste the four categories of changes into the new section
- Open the GitHub milestone corresponding to the new version
- Check each pull request and put it in the category (or categories) that it belongs in
- If a change affects the default behavior of GraphQL-Ruby in a disruptive way, add it to `### Breaking Changes` and include migration notes if possible
- Include the PR number beside the change description for future reference
- Update `lib/graphql/version.rb` with the new version number
- Commit changes to master
- Release to RubyGems
- Without 2FA 😢: `bundle exec rake release`
- With 2FA 😎: `bundle exec rake build` then `gem push pkg/graphql-.gem`, `git tag v && git push v`
- Update the website:
- Generate new API docs with `bundle exec rake apidocs:gen_version[]`
- Push them to the website with `bundle exec rake site:publish`
- Celebrate 🎊 !
graphql-ruby-1.11.10/guides/errors/ 0000775 0000000 0000000 00000000000 14141214530 0017057 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/errors/error_handling.md 0000664 0000000 0000000 00000004572 14141214530 0022406 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Errors
title: Error Handling
desc: Rescuing application errors from field resolvers
index: 3
---
You can configure your schema to rescue application errors during field resolution. Errors during batch loading will also be rescued.
__Note:__ This feature is for class-based schemas using the {% internal_link "interpreter runtime", "/queries/interpreter" %} only.
Thanks to [`@exAspArk`] for the [`graphql-errors`](https://github.com/exAspArk/graphql-errors) gem which inspired this behavior and [`@thiago-sydow`](https://github.com/thiago-sydow) who [suggested](https://github.com/rmosolgo/graphql-ruby/issues/2139#issuecomment-524913594) and implementation like this.
## Setup
Add error handling to your schema with `use GraphQL::Execution::Errors`. (This will be the default in a future graphql-ruby version.)
```ruby
class MySchema < GraphQL::Schema
# Use the new runtime & analyzers:
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
# Also use the new error handling:
use GraphQL::Execution::Errors
end
```
## Add error handlers
Handlers are added with `rescue_from` configurations in the schema:
```ruby
class MySchema < GraphQL::Schema
# ...
rescue_from(ActiveRecord::RecordNotFound) do |err, obj, args, ctx, field|
# Raise a graphql-friendly error with a custom message
raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
end
rescue_from(SearchIndex::UnavailableError) do |err, obj, args, ctx, field|
# Log the error
Bugsnag.notify(err)
# replace it with nil
nil
end
end
```
The handler is called with several arguments:
- __`err`__ is the error that was raised during field execution, then rescued
- __`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
Inside the handler, you can:
- Raise a GraphQL-friendly {{ "GraphQL::ExecutionError" | api_doc }} 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)
graphql-ruby-1.11.10/guides/errors/execution_errors.md 0000664 0000000 0000000 00000005526 14141214530 0023010 0 ustar 00root root 0000000 0000000 ---
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
{
"errors" => [ ... ]
}
```
The response may include _both_ `"data"` and `"errors"` in the case of a partial success:
```ruby
{
"data" => { ... } # parts of the query that ran successfully
"errors" => [ ... ] # errors that prevented some parts of the query from running
}
```
## When to Use Top-Level Errors
In general, top-level errors should only be used for exceptional circumstances when a developer should be made aware that the system had some kind of problem.
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" %}.
## Adding Errors to the Array
In GraphQL-Ruby, you can add entries to this array by raising `GraphQL::ExecutionError` (or a subclass of it), for example:
```ruby
raise GraphQL::ExecutionError, "Can't continue with this query"
```
When this error is raised, its `message` will be added to the `"errors"` key and GraphQL-Ruby will automatically add the `line`, `column` and `path` to it. So, the above error might be:
```ruby
{
"errors" => [
{
"message" => "Can't continue with this query",
"locations" => [
{
"line" => 2,
"column" => 10,
}
],
"path" => ["user", "login"],
}
]
}
```
## Customizing Error JSON
The default error JSON includes `"message"`, `"locations"` and `"path"`. The [forthcoming version](https://spec.graphql.org/draft/#example-fce18) of the GraphQL spec recommends putting custom data in the `"extensions"` key of the error JSON.
You can customize this in two ways:
- Pass `extensions:` when raising an error, for example:
```ruby
raise GraphQL::ExecutionError.new("Something went wrong", extensions: { "code" => "BROKEN" })
```
In this case, `"extensions" => { "code" => "BROKEN" }` will be added to the error JSON.
- Override `#to_h` in a subclass of `GraphQL::ExecutionError`, for example:
```ruby
class ServiceUnavailableError < GraphQL::ExecutionError
def to_h
super.merge({ "extensions" => {"code" => "SERVICE_UNAVAILABLE"} })
end
end
```
Now, `"extensions" => { "code" => "SERVICE_UNAVAILABLE" }` will be added to the error JSON.
graphql-ruby-1.11.10/guides/errors/overview.md 0000664 0000000 0000000 00000005476 14141214530 0021263 0 ustar 00root root 0000000 0000000 ---
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/
---
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.
## Validation Errors
Because GraphQL is strongly typed, it performs validation of all queries before executing them. If an incoming query is invalid, it isn't executed. Instead, a response is sent back with `"errors"`:
```ruby
{
"errors" => [ ... ]
}
```
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.
## 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 Invariants
While GraphQL-Ruby is executing a query, some constraints must be satisfied. For example:
- 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" %}.
## 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" %}.
## 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" %}.
## Unhandled Errors (Crashes)
When a `raise`d error is not `rescue`d, the GraphQL query crashes entirely and the surrounding code (like a Rails controller) must handle the exception.
For example, Rails will probably return a generic `500` page.
## Errors as Data
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" %}
graphql-ruby-1.11.10/guides/errors/type_errors.md 0000664 0000000 0000000 00000002352 14141214530 0021760 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Errors
title: Type Errors
desc: Handling type errors
index: 3
---
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.
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:
```ruby
class MySchema < GraphQL::Schema
def self.type_error(err, query_ctx)
# Handle a failed runtime type coercion
end
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 }}).
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 }}
An object that fails type resolution is treated as `nil`.
graphql-ruby-1.11.10/guides/faq.md 0000664 0000000 0000000 00000001541 14141214530 0016635 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
title: FAQ
other: true
desc: How to do common tasks
---
Returning Route URLs
====================
With GraphQL there is less of a need to include resource URLs to other REST resources, however sometimes you want to use Rails routing to include a URL as one of your fields. A common use case would be to build HTML format URLs to render a link in your React UI. In that case you can add the Rails route helpers to the execution context as shown below.
Example
-------
```ruby
class Types::UserType < Types::BaseObject
field :profile_url, String, null: false
def profile_url
context[:routes].user_url(object)
end
end
# Add the url helpers to `context`:
MySchema.execute(
params[:query],
variables: params[:variables],
context: {
routes: Rails.application.routes.url_helpers,
# ...
},
)
```
graphql-ruby-1.11.10/guides/fields/ 0000775 0000000 0000000 00000000000 14141214530 0017011 5 ustar 00root root 0000000 0000000 graphql-ruby-1.11.10/guides/fields/arguments.md 0000664 0000000 0000000 00000010435 14141214530 0021343 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Fields
title: Arguments
desc: Fields may take arguments as inputs
index: 10
---
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 defined with the `argument` helper. These arguments are passed as [keyword arguments](https://robots.thoughtbot.com/ruby-2-keyword-arguments) to the resolver method:
```ruby
field :search_posts, [PostType], null: false do
argument :category, String, required: true
end
def search_posts(category:)
Post.where(category: category).limit(10)
end
```
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
```
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
```
**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
```
Note argument deprecation is a stage 2 GraphQL [proposal](https://github.com/graphql/graphql-spec/pull/525) so not all clients will leverage this information.
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, required: true, as: :id
end
def post(id:)
Post.find(id)
end
```
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, required: true, 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
```
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, required: true
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, required: true, 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, required: true
end
def posts(start_year:)
# ...
end
```
Only certain types are valid for arguments:
- {{ "GraphQL::ScalarType" | api_doc }}, including built-in scalars (string, int, float, boolean, ID)
- {{ "GraphQL::EnumType" | api_doc }}
- {{ "GraphQL::InputObjectType" | api_doc }}, which allows key-value pairs as input
- {{ "GraphQL::ListType" | api_doc }}s of a valid input type
- {{ "GraphQL::NonNullType" | api_doc }}s of a valid input type
graphql-ruby-1.11.10/guides/fields/introduction.md 0000664 0000000 0000000 00000020745 14141214530 0022064 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Fields
title: Introduction
desc: Implement fields and resolvers with the Ruby DSL
index: 0
---
Object fields expose data about that object or connect the object to other objects. You can add fields to your object types with the `field(...)` class method, for example:
```ruby
field :name, String, "The unique name of this list", null: false
```
{% internal_link "Objects", "/type_definitions/objects" %} and {% internal_link "Interfaces", "/type_definitions/interfaces" %} have fields.
The different elements of field definition are addressed below:
- [Return types](#field-return-type) say what kind of data this field returns
- [Documentation](#field-documentation) includes description and deprecation notes
- [Resolution behavior](#field-resolution) hooks up Ruby code to the GraphQL field
- [Arguments](#field-arguments) allow fields to take input when they're queried
- [Extra field metadata](#extra-field-metadata) for low-level access to the GraphQL-Ruby runtime
- [Add default values for field parameters](#field-parameter-default-values)
### Field 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 required `null:` keyword:
- `null: true` 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, null: true # `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], null: true # `[Int]`, may return a list or `nil`, the list may contain a mix of `Integer`s and `nil`s
```
### Field Documentation
Fields may be documented with a __description__ and may be __deprecated__.
__Descriptions__ can be added with the `field(...)` method as a positional argument, a keyword argument, or inside the block:
```ruby
# 3rd positional argument
field :name, String, "The name of this thing", null: false
# `description:` keyword
field :name, String, null: false,
description: "The name of this thing"
# inside the block
field :name, String, null: false do
description "The name of this thing"
end
```
__Deprecated__ fields can be marked by adding a `deprecation_reason:` keyword argument:
```ruby
field :email, String, null: true,
deprecation_reason: "Users may have multiple emails, use `User.emails` instead."
```
Fields with a `deprecation_reason:` will appear as "deprecated" in GraphiQL.
### Field Resolution
In general, fields return Ruby values corresponding to their GraphQL return types. For example, a field with the return type `String` should return a Ruby string, and a field with the return type `[User!]!` should return a Ruby array with zero or more `User` objects in it.
By default, fields return values by:
- Trying to call a method on the underlying object; _OR_
- If the underlying object is a `Hash`, lookup a key in that hash.
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 with the `hash_key:` 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"
```
To pass-through the underlying object without calling a method on it, you can use `method: :itself`:
```ruby
field :player, User, null: false,
method: :itself
```
This is equivalent to:
```ruby
field :player, User, null: false
def player
object
end
```
If you don't want to delegate to the underlying object, you can define a method for each field:
```ruby
# Use the custom method below to resolve this field
field :total_games_played, Integer, null: false
def total_games_played
object.games.count
end
```
Inside the method, you can access some helper methods:
- `object` is the underlying application object (formerly `obj` to resolve functions)
- `context` is the query context (passed as `context:` when executing queries, formerly `ctx` to resolve functions)
Additionally, when you define arguments (see below), they're passed to the method definition, for example:
```ruby
# Call the custom method with incoming arguments
field :current_winning_streak, Integer, null: false do
argument :include_ties, Boolean, required: false, default_value: false
end
def current_winning_streak(include_ties:)
# Business logic goes here
end
```
As the examples above show, by default the custom method name must match the field name. If you want to use a different custom method, the `resolver_method` option is available:
```ruby
# Use the custom method with a non-default name below to resolve this field
field :total_games_played, Integer, null: false, resolver_method: :games_played
def games_played
object.games.count
end
```
`resolver_method` has two main use cases:
1. resolver re-use between multiple fields
2. dealing with method conflicts (specifically if you have fields named `context` or `object`)
Note that `resolver_method` _cannot_ be used in combination with `method` or `hash_key`.
### Field Arguments
_Arguments_ allow fields to take input to their resolution. For example:
- A `search()` field may take a `term:` argument, which is the query to use for searching, eg `search(term: "GraphQL")`
- A `user()` field may take an `id:` argument, which specifies which user to find, eg `user(id: 1)`
- An `attachments()` field may take a `type:` argument, which filters the result by file type, eg `attachments(type: PHOTO)`
Read more in the {% internal_link "Arguments guide", "/fields/arguments" %}
### Extra Field Metadata
Inside a field method, you can access some low-level objects from the GraphQL-Ruby runtime. Be warned, these APIs are subject to change, so check the changelog when updating.
A few `extras` are available:
- `ast_node`
- `graphql_name` (the field's name)
- `owner` (the type that this field belongs to)
- `lookahead` (see {% internal_link "Lookahead", "/queries/lookahead" %})
- `execution_errors`, whose `#add(err_or_msg)` method should be used for adding errors
- `argument_details` (Intepreter only), an instance of {{ "GraphQL::Execution::Interpreter::Arguments" | api_doc }} with argument metadata
- Custom extras, see below
To inject them into your field method, first, add the `extras:` option to the field definition:
```ruby
field :my_field, String, null: false, extras: [:ast_node]
```
Then add `ast_node:` keyword to the method signature:
```ruby
def my_field(ast_node:)
# ...
end
```
At runtime, the requested runtime object will be passed to the field.
__Custom extras__ are also possible. Any method on your field class can be passed to `extras: [...]`, and the value will be injected into the method. For example, `extras: [:owner]` will inject the object type who owns the field. Any new methods on your custom field class may be used, too.
### Field Parameter Default Values
The field method requires you to pass `null:` keyword argument to determine whether the field is nullable or not. For another field you may want to override `camelize`, which is `true` by default. You can override this behavior by adding a custom field with overwritten `camelize` option, which is `true` by default.
```ruby
class CustomField < GraphQL::Schema::Field
# Add `null: false` and `camelize: false` which provide default values
# in case the caller doesn't pass anything for those arguments.
# **kwargs is a catch-all that will get everything else
def initialize(*args, null: false, camelize: false, **kwargs, &block)
# Then, call super _without_ any args, where Ruby will take
# _all_ the args originally passed to this method and pass it to the super method.
super
end
end
```
graphql-ruby-1.11.10/guides/fields/limits.md 0000664 0000000 0000000 00000001462 14141214530 0020637 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Fields
title: Limits
desc: Always limit lists of items
index: 4
---
## List Fields
Always limit the number of items which can be returned from a list field. For example, use a `limit:` argument and make sure it's not too big. The `prepare:` function provides a convenient place to cap the number of items:
```ruby
field :items, [Types::ItemType] do
# Cap the number of items at 30
argument :limit, Integer, default_value: 20, prepare: ->(limit, ctx) {[limit, 30].min}
end
def items(limit:)
object.items.limit(limit)
end
```
This way, you won't hit your database for 1000 items!
## Relay Connections
Relay connections accept a {% internal_link "`max_page_size` option","/relay/connections.html#maximum-page-size" %} which limits the number of nodes.
graphql-ruby-1.11.10/guides/fields/resolvers.md 0000664 0000000 0000000 00000015033 14141214530 0021361 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
section: Fields
title: Resolvers
desc: Reusable, extendable resolution logic for complex fields
index: 9
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:
```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`.
## First, ask yourself ...
Do you really need a `Resolver`? Putting logic in a Resolver has some downsides:
- Since it's coupled to GraphQL, it's harder to test than a plain ol' Ruby object in your app
- Since the base class comes from GraphQL-Ruby, it's subject to upstream changes which may require updates in your code
Here are a few alternatives to consider:
- Put display logic (sorting, filtering, etc.) into a plain ol' Ruby class in your app, and test that class
- Hook up that object with a method, for example:
```ruby
field :recommended_items, [Types::Item], null: false
def recommended_items
ItemRecommendation.new(user: context[:viewer]).items
end
```
- If you have lots of arguments to share, use a class method to generate fields, for example:
```ruby
# Generate a field which returns a filtered, sorted list of items
def self.items_field(name, override_options)
# Prepare options
default_field_options = { type: [Types::Item], null: false }
field_options = default_field_options.merge(override_options)
# Create the field
field(name, field_options) do
argument :order_by, Types::ItemOrder, required: false
argument :category, Types::ItemCategory, required: false
# Allow an override block to add more arguments
yield self if block_given?
end
end
# Then use the generator to create a field:
items_field(:recommended_items) do |field|
field.argument :similar_to_product_id, ID, required: false
end
# Implement the field
def recommended_items
# ...
end
```
As a matter of code organization, that class method could be put in a module and shared between different classes that need it.
- If you need the _same_ logic shared between several objects, consider using a Ruby module and its `self.included` hook, for example:
```ruby
module HasRecommendedItems
def self.included(child_class)
# attach the field here
child_class.field(:recommended_items, [Types::Item], null: false)
end
# then implement the field
def recommended_items
# ...
end
end
# Add the field to some objects:
class Types::User < BaseObject
include HasRecommendedItems # adds the field
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.
## When do you really need a resolver?
So, if there are other, better options, why does `Resolver` exist? Here are a few specific advantages:
- __Isolation__. A `Resolver` is instantiated for each call to the field, so its instance variables are private to that object. If you need to use instance variables for some reason, this helps. You have a guarantee that those values won't hang around when the work is done.
- __Complex Schema Generation__. `RelayClassicMutation` (which is a `Resolver` subclass) generates input types and return types for each mutation. Using a `Resolver` class makes it easier to implement, share and extend this code generation logic.
## Using `resolver`
To add resolvers to your project, make a base class:
```ruby
# app/graphql/resolvers/base.rb
module Resolvers
class Base < GraphQL::Schema::Resolver
# if you have a custom argument class, you can attach it:
argument_class Arguments::Base
end
end
```
Then, extend it as needed:
```ruby
module Resolvers
class RecommendedItems < Resolvers::Base
type [Types::Item], null: false
argument :order_by, Types::ItemOrder, required: false
argument :category, Types::ItemCategory, required: false
def resolve(order_by: nil, category: nil)
# call your application logic here:
recommendations = ItemRecommendation.new(
viewer: context[:viewer],
recommended_for: object,
order_by: order_by,
category: category,
)
# return the list of items
recommendations.items
end
end
end
```
And attach it to your field:
```ruby
class Types::User < Types::BaseObject
field :recommended_items,
resolver: Resolvers::RecommendedItems,
description: "Items this user might like"
end
```
Since the `Resolver` lifecycle is managed by the GraphQL runtime, the best way to test it is to execute GraphQL queries and check the results.
### Nesting resolvers of the same type
You may run into cyclical loading issues when using a resolver within the definition of the type the resolver returns e.g.
```ruby
# app/graphql/types/query_type.rb
module Types
class QueryType < Types::BaseObject
field :tasks, resolver: Resolvers::TasksResolver
end
end
# app/graphql/types/task_type.rb
module Types
class TaskType < Types::BaseObject
field :title, String, null: false
field :tasks, resolver: Resolvers::TasksResolver
end
end
# app/graphql/resolvers/tasks_resolver.rb
module Resolvers
class TasksResolver < GraphQL::Schema::Resolver
type [Types::TaskType], null: false
def resolve
[]
end
end
end
```
The above can produce the following error: `Failed to build return type for Task.tasks from nil: Unexpected type input: (NilClass)`.
A simple solution is to express the type as a string in the resolver:
```ruby
module Resolvers
class TasksResolver < GraphQL::Schema::Resolver
type "[Types::TaskType]", null: false
def resolve
[]
end
end
end
```
In doing so, you can defer the loading of the type class until the nested resolver has already been loaded.
# Extensions
In cases when you want your resolvers to add some extensions to the field they resolve, you can use `extension` method, which accepts extension class and options. Multiple extensions can be configured for a single resolver.
```ruby
class GreetingExtension < GraphQL::Schema::FieldExtension
def resolve(object:, arguments:, **rest)
name = yield(object, arguments)
"#{options[:greeting]}, #{name}!"
end
end
class ResolverWithExtension < BaseResolver
type String, null: false
extension GreetingExtension, greeting: "Hi"
def resolve
"Robert"
end
end
```
graphql-ruby-1.11.10/guides/getting_started.md 0000664 0000000 0000000 00000007504 14141214530 0021262 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
title: Getting Started
section: Other
desc: Start here!
---
## Installation
You can install `graphql` from RubyGems by adding to your application's `Gemfile`:
```ruby
# Gemfile
gem "graphql"
```
Then, running `bundle install`:
```sh
$ bundle install
```
## Getting Started
On Rails, you can get started with a few [GraphQL generators](https://rmosolgo.github.io/graphql-ruby/schema/generators#graphqlinstall):
```sh
# Add graphql-ruby boilerplate and mount graphiql in development
rails g graphql:install
# Make your first object type
rails g graphql:object Post title:String rating:Int comments:[Comment]
```
Or, you can build a GraphQL server by hand:
- Define some types
- Connect them to a schema
- Execute queries with your schema
### Declare types
Types describe objects in your application and form the basis for [GraphQL's type system](https://graphql.org/learn/schema/#type-system).
```ruby
# app/graphql/types/post_type.rb
module Types
class PostType < Types::BaseObject
description "A blog post"
field :id, ID, null: false
field :title, String, null: false
# fields should be queried in camel-case (this will be `truncatedPreview`)
field :truncated_preview, String, null: false
# Fields can return lists of other objects:
field :comments, [Types::CommentType], null: true,
# And fields can have their own descriptions:
description: "This post's comments, or null if this post has comments disabled."
end
end
# app/graphql/types/comment_type.rb
module Types
class CommentType < Types::BaseObject
field :id, ID, null: false
field :post, PostType, null: false
end
end
```
### Build a Schema
Before building a schema, you have to define an [entry point to your system, the "query root"](https://graphql.org/learn/schema/#the-query-and-mutation-types):
```ruby
class QueryType < GraphQL::Schema::Object
description "The query root of this schema"
# First describe the field signature:
field :post, PostType, null: true do
description "Find a post by ID"
argument :id, ID, required: true
end
# Then provide an implementation:
def post(id:)
Post.find(id)
end
end
```
Then, build a schema with `QueryType` as the query entry point:
```ruby
class Schema < GraphQL::Schema
query QueryType
end
```
This schema is ready to serve GraphQL queries! {% internal_link "Browse the guides","/guides" %} to learn about other GraphQL Ruby features.
### Execute queries
You can execute queries from a query string:
```ruby
query_string = "
{
post(id: 1) {
id
title
truncatedPreview
}
}"
result_hash = Schema.execute(query_string)
# {
# "data" => {
# "post" => {
# "id" => 1,
# "title" => "GraphQL is nice"
# "truncatedPreview" => "GraphQL is..."
# }
# }
# }
```
See {% internal_link "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 `GraphQL::Relay` guides.
## Use with Apollo Client
[Apollo Client](https://www.apollographql.com/) is a full featured, simple to use GraphQL client with convenient integrations for popular view layers. You don't need to do anything special to connect Apollo Client to a `graphql-ruby` server.
## Use with GraphQL.js Client
[GraphQL.js Client](https://github.com/f/graphql.js) is a tiny client that is platform- and framework-agnostic. It works well with `graphql-ruby` servers, since GraphQL requests are simple query strings transported over HTTP.
graphql-ruby-1.11.10/guides/graphql-ruby-icon.png 0000664 0000000 0000000 00000010012 14141214530 0021606 0 ustar 00root root 0000000 0000000 PNG
IHDR g g A\ bKGD pHYs a a?i tIMEJ7 IDATx]}xSU&)lKIR(<Jp|DGQeR*M˂]G>gQaGyQOqgG|`gwMR*|5G{Is~&iIOy;:0`0`HwW %yݜGbXLa`8Ol
5|L*o%`03cVޮ $9[LK0,滚|ky)[=aT<J+u _%侖"mw,cIM" tۓyYpl?_5~ԊpQCGiK%c( f'{ifhk%G$B \TҊxb `Jh㡂L ky]R"v$f&@(Ia2] s0n0i*XטJg-ef߰73f ^bҶPG'y }~:4Mr0|1"d7<&^'mНؙfd8&an
d Ӏ ^헅y@@.KJƌjr6^M~eh)jBUyx+X{T*(@4t$!EtIkyB V(_&K,I9
ׄRq`o\LPL#A\T7'MUĸA,6E-{Pr1f]|3C^!ձ7U i+peL}Gp.aVW3nV(i0c^t8j81 ,܁r|Y,M?Q7y{286nVe!z
LN'O
| poHl]qY^2U/TM"oir<䄹]R=0I L7=P<.!rBeDPMJڥ)qR?d"6jSwc=]2nEϚj;;; uUVpuh=-hjlΗ2JNݱRvB0 @czͅ@ͱ(B