summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-29 06:06:31 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-29 06:06:31 +0000
commit2ac93cb80c4c0a57fde86de8262b569d1e9b9e51 (patch)
tree3f74cb04801cb4dcea27c8e1b4d24b783b4f1ec3 /doc
parent23d8718bf3a114f7b832a9c493b1efcdc6decedb (diff)
downloadgitlab-ce-2ac93cb80c4c0a57fde86de8262b569d1e9b9e51.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc')
-rw-r--r--doc/development/api_graphql_styleguide.md96
-rw-r--r--doc/development/fe_guide/graphql.md44
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md12
3 files changed, 149 insertions, 3 deletions
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 1cf2ca3667d..1ef0b928820 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -1,5 +1,13 @@
# GraphQL API
+## How GitLab implements GraphQL
+
+We use the [graphql-ruby gem](https://graphql-ruby.org/) written by [Robert Mosolgo](https://github.com/rmosolgo/).
+
+All GraphQL queries are directed to a single endpoint
+([`app/controllers/graphql_controller.rb#execute`](https://gitlab.com/gitlab-org/gitlab/blob/master/app%2Fcontrollers%2Fgraphql_controller.rb)),
+which is exposed as an API endpoint at `/api/graphql`.
+
## Deep Dive
In March 2019, Nick Thomas hosted a [Deep Dive](https://gitlab.com/gitlab-org/create-stage/issues/1)
@@ -22,8 +30,31 @@ add a `HTTP_PRIVATE_TOKEN` header.
## Types
+We use a code-first schema, and we declare what type everything is in Ruby.
+
+For example, `app/graphql/types/issue_type.rb`:
+
+```ruby
+graphql_name 'Issue'
+
+field :iid, GraphQL::ID_TYPE, null: false
+field :title, GraphQL::STRING_TYPE, null: false
+
+# we also have a method here that we've defined, that extends `field`
+markdown_field :title_html, null: true
+field :description, GraphQL::STRING_TYPE, null: true
+markdown_field :description_html, null: true
+```
+
+We give each type a name (in this case `Issue`).
+
+The `iid`, `title` and `description` are _scalar_ GraphQL types.
+`iid` is a `GraphQL::ID_TYPE`, a special string type that signifies a unique ID.
+`title` and `description` are regular `GraphQL::STRING_TYPE` types.
+
When exposing a model through the GraphQL API, we do so by creating a
-new type in `app/graphql/types`.
+new type in `app/graphql/types`. You can also declare custom GraphQL data types
+for scalar data types (e.g. `TimeType`).
When exposing properties in a type, make sure to keep the logic inside
the definition as minimal as possible. Instead, consider moving any
@@ -293,6 +324,8 @@ If the:
- Resource is part of a collection, the collection will be filtered to
exclude the objects that the user's authorization checks failed against.
+Also see [authorizing resources in a mutation](#authorizing-resources).
+
TIP: **Tip:**
Try to load only what the currently authenticated user is allowed to
view with our existing finders first, without relying on authorization
@@ -391,6 +424,11 @@ end
## Resolvers
+We define how the application serves the response using _resolvers_
+stored in the `app/graphql/resolvers` directory.
+The resolver provides the actual implementation logic for retrieving
+the objects in question.
+
To find objects to display in a field, we can add resolvers to
`app/graphql/resolvers`.
@@ -618,7 +656,61 @@ it 'returns a successful response' do
end
```
+## Notes about Query flow and GraphQL infrastructure
+
+GitLab's GraphQL infrastructure can be found in `lib/gitlab/graphql`.
+
+[Instrumentation](https://graphql-ruby.org/queries/instrumentation.html) is functionality
+that wraps around a query being executed. It is implemented as a module that uses the `Instrumentation` class.
+
+Example: `Present`
+
+```ruby
+module Present
+ #... some code above...
+
+ def self.use(schema_definition)
+ schema_definition.instrument(:field, Instrumentation.new)
+ end
+end
+```
+
+A [Query Analyzer](https://graphql-ruby.org/queries/analysis.html#analyzer-api) contains a series
+of callbacks to validate queries before they are executed. Each field can pass through
+the analyzer, and the final value is also available to you.
+
+[Multiplex queries](https://graphql-ruby.org/queries/multiplex.html) enable
+multiple queries to be sent in a single request. This reduces the number of requests sent to the server.
+(there are custom Multiplex Query Analyzers and Multiplex Instrumentation provided by graphql-ruby).
+
+### Query limits
+
+Queries and mutations are limited by depth, complexity, and recursion
+to protect server resources from overly ambitious or malicious queries.
+These values can be set as defaults and overridden in specific queries as needed.
+The complexity values can be set per object as well, and the final query complexity is
+evaluated based on how many objects are being returned. This is useful
+for objects that are expensive (e.g. requiring Gitaly calls).
+
+For example, a conditional complexity method in a resolver:
+
+```ruby
+def self.resolver_complexity(args, child_complexity:)
+ complexity = super
+ complexity += 2 if args[:labelName]
+
+ complexity
+end
+```
+
+More about complexity:
+[graphql-ruby docs](https://graphql-ruby.org/queries/complexity_and_depth.html)
+
## Documentation and Schema
+Our schema is located at `app/graphql/gitlab_schema.rb`.
+See the [schema reference](../api/graphql/reference/index.md) for details.
+
+This generated GraphQL documentation needs to be updated when the schema changes.
For information on generating GraphQL documentation and schema files, see
-[Rake tasks related to GraphQL](rake_tasks.md#update-graphql-documentation-and-schema-definitions).
+[updating the schema documentation](rake_tasks.md#update-graphql-documentation-and-schema-definitions).
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 894a613ec2d..b813ea24750 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -39,6 +39,50 @@ To distinguish queries from mutations and fragments, the following naming conven
- `addUser.mutation.graphql` for mutations;
- `basicUser.fragment.graphql` for fragments.
+GraphQL:
+
+- Queries are stored in `(ee/)app/assets/javascripts/` under the feature. For example, `respository/queries`. Frontend components can use these stored queries.
+- Mutations are stored in
+ `(ee/)app/assets/javascripts/<subfolders>/<name of mutation>.mutation.graphql`.
+
+### Fragments
+
+Fragments are a way to make your complex GraphQL queries more readable and re-usable.
+They can be stored in a separate file and imported.
+
+For example, a fragment that references another fragment:
+
+```ruby
+fragment BaseEpic on Epic {
+ id
+ iid
+ title
+ webPath
+ relativePosition
+ userPermissions {
+ adminEpic
+ createEpic
+ }
+}
+
+fragment EpicNode on Epic {
+ ...BaseEpic
+ state
+ reference(full: true)
+ relationPath
+ createdAt
+ closedAt
+ hasChildren
+ hasIssues
+ group {
+ fullPath
+ }
+}
+```
+
+More about fragments:
+[GraphQL Docs](https://graphql.org/learn/queries/#fragments)
+
## Usage in Vue
To use Vue Apollo, import the [Vue Apollo][vue-apollo] plugin as well
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index 2457d8ada5a..16a45bc5ef0 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -26,7 +26,17 @@ If you don't exactly understand what we mean by **not everything needs to happen
At GitLab we respect the [test pyramid](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md), and so, we recommend you check the code coverage of a specific feature before writing end-to-end tests, for both [CE](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles) and [EE](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles) projects.
-Sometimes you may notice that there is already good coverage in other test levels, and we can stay confident that if we break a feature, we will still have quick feedback about it, even without having end-to-end tests.
+Sometimes you may notice that there is already good coverage in lower test levels, and we can stay confident that if we break a feature, we will still have quick feedback about it, even without having end-to-end tests.
+
+> For analyzing the code coverage, you will also need to understand which application files implement specific functionalities.
+
+#### Some other guidelines are as follows
+
+- Take a look at the [How to test at the correct level?](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md#how-to-test-at-the-correct-level) section of the [Testing levels](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md) document
+
+- Look into the frequency in which such a feature is changed (_Stable features that don't change very often might not be worth covering with end-to-end tests if they're already covered in lower levels_)
+
+- Finally, discuss with the developer(s) involved in developing the feature and the tests themselves, to get their feeling
If after this analysis you still think that end-to-end tests are needed, keep reading.