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
The [example users query](#set-up-the-graphiql-explorer) looks for a subset of users in
a GitLab instance either by username or
[global ID](../../development/api_graphql_styleguide.md#exposing-global-ids). The query
includes:
[Global ID](../../development/api_graphql_styleguide.md#global-ids).
The query includes:
- [`pageInfo`](#pageinfo)
- [`nodes`](#nodes)
......
......@@ -59,8 +59,9 @@ The GitLab GraphQL API can be used to perform:
- [Mutations](#mutations) for creating, updating, and deleting data.
NOTE: **Note:**
In the GitLab GraphQL API, `id` generally refers to a global ID,
which is an object identifier in the format of `gid://gitlab/Issue/123`.
In the GitLab GraphQL API, `id` refers to a
[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
available for clients to query and their corresponding data types.
......
......@@ -36,6 +36,19 @@ can be shared.
It is also possible to add a `private_token` to the querystring, or
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
We use a code-first schema, and we declare what type everything is in Ruby.
......@@ -106,18 +119,28 @@ Further reading:
### Exposing Global IDs
When exposing an `ID` field on a type, we will by default try to
expose a global ID by calling `to_global_id` on the resource being
rendered.
In keeping with GitLab's use of [Global IDs](#global-ids), always convert
database primary key IDs into Global IDs when you expose them.
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
type for which you are exposing an ID. Please make sure that when
exposing a `GraphQL::ID_TYPE` using a custom method that it is
globally unique.
Fields that are not named `id` need to be manually converted. We can do this using
[`Gitlab::GlobalID.build`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/global_id.rb),
or by calling `#to_global_id` on an object that has mixed in the
`GlobalID::Identification` module.
The records that are exposing a `full_path` as an `ID_TYPE` are one of
these exceptions. Since the full path is a unique identifier for a
`Project` or `Namespace`.
Using an example from
[`Types::Notes::DiscussionType`](https://gitlab.com/gitlab-org/gitlab/-/blob/3c95bd9/app/graphql/types/notes/discussion_type.rb#L24-26):
```ruby
field :reply_id, GraphQL::ID_TYPE
def reply_id
::Gitlab::GlobalId.build(object, id: object.reply_id)
end
```
### Connection Types
......@@ -654,15 +677,8 @@ the objects in question.
To find objects to display in a field, we can add resolvers to
`app/graphql/resolvers`.
Arguments can be defined within the resolver, those arguments will be
made available to the fields using the resolver. When exposing a model
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.
Arguments can be defined within the resolver in the same way as in a mutation.
See the [Mutation arguments](#object-identifier-arguments) section.
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
cannot modify data in a regular GraphQL-query. We can however in a
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
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
### Arguments
Arguments required by the mutation can be defined as arguments
required for a field. These will be wrapped up in an input type for
the mutation. For example, the `Mutations::MergeRequests::SetWip`
with GraphQL-name `MergeRequestSetWip` defines these arguments:
Arguments for a mutation are defined using `argument`.
Example:
```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
argument :project_path, GraphQL::ID_TYPE,
......@@ -832,12 +868,19 @@ argument :wip,
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
`clientMutationId`.
These arguments are then passed to the `resolve` method of a mutation
as keyword arguments.
### Object identifier 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
......
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