Commit 8aff254b authored by Luke Duncalfe's avatar Luke Duncalfe Committed by Evan Read

Clarify use of object identifiers in GraphQL API

parent 5a7553f7
...@@ -8,8 +8,8 @@ guidance on getting started from the [command line](getting_started.md#command-l ...@@ -8,8 +8,8 @@ guidance on getting started from the [command line](getting_started.md#command-l
The [example users query](#set-up-the-graphiql-explorer) looks for a subset of users in The [example users query](#set-up-the-graphiql-explorer) looks for a subset of users in
a GitLab instance either by username or a GitLab instance either by username or
[global ID](../../development/api_graphql_styleguide.md#exposing-global-ids). The query [Global ID](../../development/api_graphql_styleguide.md#global-ids).
includes: The query includes:
- [`pageInfo`](#pageinfo) - [`pageInfo`](#pageinfo)
- [`nodes`](#nodes) - [`nodes`](#nodes)
......
...@@ -59,8 +59,9 @@ The GitLab GraphQL API can be used to perform: ...@@ -59,8 +59,9 @@ The GitLab GraphQL API can be used to perform:
- [Mutations](#mutations) for creating, updating, and deleting data. - [Mutations](#mutations) for creating, updating, and deleting data.
NOTE: **Note:** NOTE: **Note:**
In the GitLab GraphQL API, `id` generally refers to a global ID, In the GitLab GraphQL API, `id` refers to a
which is an object identifier in the format of `gid://gitlab/Issue/123`. [Global ID](https://graphql.org/learn/global-object-identification/),
which is an object identifier in the format of `"gid://gitlab/Issue/123"`.
[GitLab's GraphQL Schema](reference/index.md) outlines which objects and fields are [GitLab's GraphQL Schema](reference/index.md) outlines which objects and fields are
available for clients to query and their corresponding data types. available for clients to query and their corresponding data types.
......
...@@ -36,6 +36,19 @@ can be shared. ...@@ -36,6 +36,19 @@ can be shared.
It is also possible to add a `private_token` to the querystring, or It is also possible to add a `private_token` to the querystring, or
add a `HTTP_PRIVATE_TOKEN` header. add a `HTTP_PRIVATE_TOKEN` header.
## Global IDs
GitLab's GraphQL API uses Global IDs (i.e: `"gid://gitlab/MyObject/123"`)
and never database primary key IDs.
Global ID is [a standard](https://graphql.org/learn/global-object-identification/)
used for caching and fetching in client-side libraries.
See also:
- [Exposing Global IDs](#exposing-global-ids).
- [Mutation arguments](#object-identifier-arguments).
## Types ## Types
We use a code-first schema, and we declare what type everything is in Ruby. We use a code-first schema, and we declare what type everything is in Ruby.
...@@ -106,18 +119,28 @@ Further reading: ...@@ -106,18 +119,28 @@ Further reading:
### Exposing Global IDs ### Exposing Global IDs
When exposing an `ID` field on a type, we will by default try to In keeping with GitLab's use of [Global IDs](#global-ids), always convert
expose a global ID by calling `to_global_id` on the resource being database primary key IDs into Global IDs when you expose them.
rendered.
All fields named `id` are
[converted automatically](https://gitlab.com/gitlab-org/gitlab/-/blob/b0f56e7/app/graphql/types/base_object.rb#L11-14)
into the object's Global ID.
To override this behavior, you can implement an `id` method on the Fields that are not named `id` need to be manually converted. We can do this using
type for which you are exposing an ID. Please make sure that when [`Gitlab::GlobalID.build`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/global_id.rb),
exposing a `GraphQL::ID_TYPE` using a custom method that it is or by calling `#to_global_id` on an object that has mixed in the
globally unique. `GlobalID::Identification` module.
The records that are exposing a `full_path` as an `ID_TYPE` are one of Using an example from
these exceptions. Since the full path is a unique identifier for a [`Types::Notes::DiscussionType`](https://gitlab.com/gitlab-org/gitlab/-/blob/3c95bd9/app/graphql/types/notes/discussion_type.rb#L24-26):
`Project` or `Namespace`.
```ruby
field :reply_id, GraphQL::ID_TYPE
def reply_id
::Gitlab::GlobalId.build(object, id: object.reply_id)
end
```
### Connection Types ### Connection Types
...@@ -654,15 +677,8 @@ the objects in question. ...@@ -654,15 +677,8 @@ the objects in question.
To find objects to display in a field, we can add resolvers to To find objects to display in a field, we can add resolvers to
`app/graphql/resolvers`. `app/graphql/resolvers`.
Arguments can be defined within the resolver, those arguments will be Arguments can be defined within the resolver in the same way as in a mutation.
made available to the fields using the resolver. When exposing a model See the [Mutation arguments](#object-identifier-arguments) section.
that had an internal ID (`iid`), prefer using that in combination with
the namespace path as arguments in a resolver over a database
ID. Otherwise use a [globally unique ID](#exposing-global-ids).
We already have a `FullPathLoader` that can be included in other
resolvers to quickly find Projects and Namespaces which will have a
lot of dependent objects.
To limit the amount of queries performed, we can use `BatchLoader`. To limit the amount of queries performed, we can use `BatchLoader`.
...@@ -751,10 +767,6 @@ actions. In the same way a GET-request should not modify data, we ...@@ -751,10 +767,6 @@ actions. In the same way a GET-request should not modify data, we
cannot modify data in a regular GraphQL-query. We can however in a cannot modify data in a regular GraphQL-query. We can however in a
mutation. mutation.
To find objects for a mutation, arguments need to be specified. As with
[resolvers](#resolvers), prefer using internal ID or, if needed, a
global ID rather than the database ID.
### Building Mutations ### Building Mutations
Mutations live in `app/graphql/mutations` ideally grouped per Mutations live in `app/graphql/mutations` ideally grouped per
...@@ -809,10 +821,34 @@ If you need advice for mutation naming, canvass the Slack `#graphql` channel for ...@@ -809,10 +821,34 @@ If you need advice for mutation naming, canvass the Slack `#graphql` channel for
### Arguments ### Arguments
Arguments required by the mutation can be defined as arguments Arguments for a mutation are defined using `argument`.
required for a field. These will be wrapped up in an input type for
the mutation. For example, the `Mutations::MergeRequests::SetWip` Example:
with GraphQL-name `MergeRequestSetWip` defines these arguments:
```ruby
argument :my_arg, GraphQL::STRING_TYPE,
required: true,
description: "A description of the argument"
```
Each GraphQL `argument` defined will be passed to the `#resolve` method
of a mutation as keyword arguments.
Example:
```ruby
def resolve(my_arg:)
# Perform mutation ...
end
```
`graphql-ruby` will automatically wrap up arguments into an
[input type](https://graphql.org/learn/schema/#input-types).
For example, the
[`mergeRequestSetWip` mutation](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/merge_requests/set_wip.rb)
defines these arguments (some
[through inheritance](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/merge_requests/base.rb)):
```ruby ```ruby
argument :project_path, GraphQL::ID_TYPE, argument :project_path, GraphQL::ID_TYPE,
...@@ -832,12 +868,19 @@ argument :wip, ...@@ -832,12 +868,19 @@ argument :wip,
DESC DESC
``` ```
This would automatically generate an input type called These arguments automatically generate an input type called
`MergeRequestSetWipInput` with the 3 arguments we specified and the `MergeRequestSetWipInput` with the 3 arguments we specified and the
`clientMutationId`. `clientMutationId`.
These arguments are then passed to the `resolve` method of a mutation ### Object identifier arguments
as keyword arguments.
In keeping with GitLab's use of [Global IDs](#global-ids), mutation
arguments should use Global IDs to identify an object and never database
primary key IDs.
Where an object has an `iid`, prefer to use the `full_path` or `group_path`
of its parent in combination with its `iid` as arguments to identify an
object rather than its `id`.
### Fields ### Fields
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment