diff options
Diffstat (limited to 'doc/development/api_graphql_styleguide.md')
-rw-r--r-- | doc/development/api_graphql_styleguide.md | 95 |
1 files changed, 89 insertions, 6 deletions
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md index 18fc0fb7d33..3d4c033e676 100644 --- a/doc/development/api_graphql_styleguide.md +++ b/doc/development/api_graphql_styleguide.md @@ -49,6 +49,20 @@ See also: - [Exposing Global IDs](#exposing-global-ids). - [Mutation arguments](#object-identifier-arguments). +We have a custom scalar type (`Types::GlobalIDType`) which should be used as the +type of input and output arguments when the value is a `GlobalID`. The benefits +of using this type instead of `ID` are: + +- it validates that the value is a `GlobalID` +- it parses it into a `GlobalID` before passing it to user code +- it can be parameterized on the type of the object (e.g. + `GlobalIDType[Project]`) which offers even better validation and security. + +Consider using this type for all new arguments and result types. Remember that +it is perfectly possible to parameterize this type with a concern or a +supertype, if you want to accept a wider range of objects (e.g. +`GlobalIDType[Issuable]` vs `GlobalIDType[Issue]`). + ## Types We use a code-first schema, and we declare what type everything is in Ruby. @@ -371,8 +385,8 @@ end GitLab's GraphQL API is versionless, which means we maintain backwards compatibility with older versions of the API with every change. Rather than removing a field or [enum value](#enums), we need to _deprecate_ it instead. -In future, GitLab -[may remove deprecated parts of the schema](https://gitlab.com/gitlab-org/gitlab/-/issues/32292). +The deprecated parts of the schema can then be removed in a future release +in accordance with [GitLab's deprecation process](../api/graphql/index.md#deprecation-process). Fields and enum values are deprecated using the `deprecated` property. The value of the property is a `Hash` of: @@ -472,6 +486,28 @@ end Enum values can be deprecated using the [`deprecated` keyword](#deprecating-fields-and-enum-values). +### Defining GraphQL enums dynamically from Rails enums + +If your GraphQL enum is backed by a [Rails enum](creating_enums.md), then consider +using the Rails enum to dynamically define the GraphQL enum values. Doing so +binds the GraphQL enum values to the Rails enum definition, so if values are +ever added to the Rails enum then the GraphQL enum automatically reflects the change. + +Example: + +```ruby +module Types + class IssuableSeverityEnum < BaseEnum + graphql_name 'IssuableSeverity' + description 'Incident severity' + + ::IssuableSeverity.severities.keys.each do |severity| + value severity.upcase, value: severity, description: "#{severity.titleize} severity" + end + end +end +``` + ## JSON When data to be returned by GraphQL is stored as @@ -780,6 +816,25 @@ to advertise the need for lookahead: For an example of real world use, please see [`ResolvesMergeRequests`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/concerns/resolves_merge_requests.rb). +### Negated arguments + +Negated filters can filter some resources (for example, find all issues that +have the `bug` label, but don't have the `bug2` label assigned). The `not` +argument is the preferred syntax to pass negated arguments: + +```graphql +issues(labelName: "bug", not: {labelName: "bug2"}) { + nodes { + id + title + } +} +``` + +To avoid duplicated argument definitions, you can place these arguments in a reusable module (or +class, if the arguments are nested). Alternatively, you can consider to add a +[helper resolver method](https://gitlab.com/gitlab-org/gitlab/-/issues/258969). + ## Pass a parent object into a child Presenter Sometimes you need to access the resolved query parent in a child context to compute fields. Usually the parent is only @@ -827,10 +882,39 @@ mutation. ### Building Mutations -Mutations live in `app/graphql/mutations` ideally grouped per +Mutations are stored in `app/graphql/mutations`, ideally grouped per resources they are mutating, similar to our services. They should inherit `Mutations::BaseMutation`. The fields defined on the mutation -will be returned as the result of the mutation. +are returned as the result of the mutation. + +#### Update mutation granularity + +GitLab's service-oriented architecture means that most mutations call a Create, Delete, or Update +service, for example `UpdateMergeRequestService`. +For Update mutations, a you might want to only update one aspect of an object, and thus only need a +_fine-grained_ mutation, for example `MergeRequest::SetWip`. + +It's acceptable to have both fine-grained mutations and coarse-grained mutations, but be aware +that too many fine-grained mutations can lead to organizational challenges in maintainability, code +comprehensibility, and testing. +Each mutation requires a new class, which can lead to technical debt. +It also means the schema becomes very big, and we want users to easily navigate our schema. +As each new mutation also needs tests (including slower request integration tests), adding mutations +slows down the test suite. + +To minimize changes: + +- Use existing mutations, such as `MergeRequest::Update`, when available. +- Expose existing services as a coarse-grained mutation. + +When a fine-grained mutation might be more appropriate: + +- Modifying a property that requires specific permissions or other specialized logic. +- Exposing a state-machine-like transition (locking issues, merging MRs, closing epics, etc). +- Accepting nested properties (where we accept properties for a child object). +- The semantics of the mutation can be expressed clearly and concisely. + +See [issue #233063](https://gitlab.com/gitlab-org/gitlab/-/issues/233063) for further context. ### Naming conventions @@ -1361,5 +1445,4 @@ For information on generating GraphQL documentation and schema files, see [updating the schema documentation](rake_tasks.md#update-graphql-documentation-and-schema-definitions). To help our readers, you should also add a new page to our [GraphQL API](../api/graphql/index.md) documentation. -For guidance, see the [GraphQL API](documentation/styleguide.md#graphql-api) section -of our documentation style guide. +For guidance, see the [GraphQL API](documentation/graphql_styleguide.md) page. |