Skip to content

Deprecate GraphQL ID/GlobalID compatibility

Deprecation Summary

See #257883 (closed)

In !36209 (merged) a compatibility layer was introduced to allow us to change the types of arguments from ID_TYPE to GlobalIDType[T]. This requires us to be careful and add lots of explicit coercions.

Breaking Change

Users who wrote GraphQL queries using ID types in query signatures will be affected if they are used to provide arguments for any of these fields:

Query.snippets(ids: [SnippetID!])
Query.snippets(authorId: UserID)
Query.snippets(projectId: ProjectID)
Query.milestone(id: MilestoneID!)
Query.containerRepository(id: ContainerRepositoryID!)
Query.package(id: PackagesPackageID!)
Query.user(id: UserID)
Query.issue(id: IssueID!)
Query.mergeRequest(id: MergeRequestID!)
Query.runnerSetup(projectId: ProjectID)
Query.runnerSetup(groupId: GroupID)
Query.runner(id: CiRunnerID!)
Query.timelogs(projectId: ProjectID)
Query.timelogs(groupId: GroupID)
Query.boardList(id: ListID!)
Query.iteration(id: IterationID!)
Query.vulnerabilities(scannerId: [VulnerabilitiesScannerID!])
Query.vulnerabilities(clusterId: [ClustersClusterID!])
Query.vulnerabilities(clusterAgentId: [ClustersAgentID!])
Query.vulnerability(id: VulnerabilityID!)
Query.devopsAdoptionEnabledNamespaces(displayNamespaceId: NamespaceID)
Query.ciMinutesUsage(namespaceId: NamespaceID)
Project.sentryDetailedError(id: GitlabErrorTrackingDetailedErrorID!)
Project.snippets(ids: [SnippetID!])
Project.boards(id: BoardID)
Project.board(id: BoardID!)
Project.alertManagementHttpIntegrations(id: AlertManagementHttpIntegrationID)
Project.timelogs(projectId: ProjectID)
Project.timelogs(groupId: GroupID)
Project.vulnerabilities(scannerId: [VulnerabilitiesScannerID!])
Project.vulnerabilities(clusterId: [ClustersClusterID!])
Project.vulnerabilities(clusterAgentId: [ClustersAgentID!])
Project.vulnerabilitySeveritiesCount(scannerId: [VulnerabilitiesScannerID!])
Project.iterations(iterationCadenceIds: [IterationsCadenceID!])
Project.iterationCadences(id: IterationsCadenceID)
Project.dastProfile(id: DastProfileID!)
Project.dastSiteProfile(id: DastSiteProfileID!)
Project.incidentManagementEscalationPolicy(id: IncidentManagementEscalationPolicyID!)
Project.incidentManagementTimelineEvents(incidentId: IssueID!)
Project.incidentManagementTimelineEvent(incidentId: IssueID!)
Project.incidentManagementTimelineEvent(id: IncidentManagementTimelineEventID!)
Project.networkPolicies(environmentId: EnvironmentID)
Namespace.complianceFrameworks(id: ComplianceManagementFrameworkID)
Namespace.complianceFrameworks(id: ComplianceManagementFrameworkID)
Group.boards(id: BoardID)
Group.board(id: BoardID!)
Group.timelogs(projectId: ProjectID)
Group.timelogs(groupId: GroupID)
Group.epicBoard(id: BoardsEpicBoardID!)
Group.iterations(iterationCadenceIds: [IterationsCadenceID!])
Group.iterationCadences(id: IterationsCadenceID)
Group.vulnerabilities(scannerId: [VulnerabilitiesScannerID!])
Group.vulnerabilities(clusterId: [ClustersClusterID!])
Group.vulnerabilities(clusterAgentId: [ClustersAgentID!])
Group.vulnerabilitySeveritiesCount(scannerId: [VulnerabilitiesScannerID!])
User.authoredMergeRequests(projectId: ProjectID)
User.assignedMergeRequests(projectId: ProjectID)
User.reviewRequestedMergeRequests(projectId: ProjectID)
User.snippets(ids: [SnippetID!])
User.timelogs(projectId: ProjectID)
User.timelogs(groupId: GroupID)
MemberInterface.mergeRequestInteraction(id: MergeRequestID!)
MemberInterface.mergeRequestInteraction(id: MergeRequestID!)
MemberInterface.mergeRequestInteraction(id: MergeRequestID!)
Design.versions(earlierOrEqualToId: DesignManagementVersionID)
DesignVersion.designsAtVersion(ids: [DesignManagementDesignID!])
DesignVersion.designAtVersion(designId: DesignManagementDesignID)
DesignVersion.designAtVersion(id: DesignManagementDesignAtVersionID)
Pipeline.job(id: JobID)
User.authoredMergeRequests(projectId: ProjectID)
User.assignedMergeRequests(projectId: ProjectID)
User.reviewRequestedMergeRequests(projectId: ProjectID)
User.snippets(ids: [SnippetID!])
User.timelogs(projectId: ProjectID)
User.timelogs(groupId: GroupID)
User.authoredMergeRequests(projectId: ProjectID)
User.assignedMergeRequests(projectId: ProjectID)
User.reviewRequestedMergeRequests(projectId: ProjectID)
User.snippets(ids: [SnippetID!])
User.timelogs(projectId: ProjectID)
User.timelogs(groupId: GroupID)
User.authoredMergeRequests(projectId: ProjectID)
User.assignedMergeRequests(projectId: ProjectID)
User.reviewRequestedMergeRequests(projectId: ProjectID)
User.snippets(ids: [SnippetID!])
User.timelogs(projectId: ProjectID)
User.timelogs(groupId: GroupID)
DesignCollection.designs(atVersion: DesignManagementVersionID)
DesignCollection.designs(ids: [DesignManagementDesignID!])
DesignCollection.versions(earlierOrEqualToId: DesignManagementVersionID)
DesignCollection.version(id: DesignManagementVersionID)
DesignCollection.designAtVersion(id: DesignManagementDesignAtVersionID!)
DesignCollection.design(id: DesignManagementDesignID)
IncidentManagementOncallSchedule.rotation(id: IncidentManagementOncallRotationID!)
Board.lists(id: ListID)
EpicBoard.lists(id: BoardsEpicListID)
SentryErrorCollection.detailedError(id: GitlabErrorTrackingDetailedErrorID!)
SentryErrorCollection.errorStackTrace(id: GitlabErrorTrackingDetailedErrorID!)
DesignManagement.version(id: DesignManagementVersionID!)
DesignManagement.designAtVersion(id: DesignManagementDesignAtVersionID!)
InstanceSecurityDashboard.vulnerabilitySeveritiesCount(scannerId: [VulnerabilitiesScannerID!])
Subscription.issuableAssigneesUpdated(issuableId: IssuableID!)
Subscription.issueCrmContactsUpdated(issuableId: IssuableID!)
Subscription.issuableTitleUpdated(issuableId: IssuableID!)

The list of query field arguments that have the ID type and do not need to be updated is:

Query.project(fullPath: ID!)
Query.projects(ids: [ID!])
Query.group(fullPath: ID!)
Query.namespace(fullPath: ID!)
Query.users(ids: [ID!])
Query.ciConfig(projectPath: ID!)
Query.vulnerabilities(projectId: [ID!])
Project.issues(iterationId: [ID])
Project.milestones(ids: [ID!])
Project.issue(iterationId: [ID])
Project.pipeline(iid: ID)
Project.vulnerabilities(projectId: [ID!])
Project.vulnerabilitySeveritiesCount(projectId: [ID!])
Project.requirement(iid: ID)
Project.requirement(iids: [ID!])
Project.requirements(iid: ID)
Project.requirements(iids: [ID!])
Project.iterations(id: ID)
Project.iterations(iid: ID)
Project.incidentManagementOncallSchedules(iids: [ID!])
Namespace.projects(ids: [ID!])
Namespace.projects(ids: [ID!])
Group.issues(iterationId: [ID])
Group.milestones(ids: [ID!])
Group.epic(iid: ID)
Group.epic(iids: [ID!])
Group.epics(iid: ID)
Group.epics(iids: [ID!])
Group.iterations(id: ID)
Group.iterations(iid: ID)
Group.vulnerabilities(projectId: [ID!])
Group.vulnerabilitySeveritiesCount(projectId: [ID!])
User.todos(authorId: [ID!])
User.todos(projectId: [ID!])
User.todos(groupId: [ID!])
Pipeline.testSuite(buildIds: [ID!]!)
User.todos(authorId: [ID!])
User.todos(projectId: [ID!])
User.todos(groupId: [ID!])
User.todos(authorId: [ID!])
User.todos(projectId: [ID!])
User.todos(groupId: [ID!])
User.todos(authorId: [ID!])
User.todos(projectId: [ID!])
User.todos(groupId: [ID!])
AlertManagementAlert.todos(authorId: [ID!])
AlertManagementAlert.todos(projectId: [ID!])
AlertManagementAlert.todos(groupId: [ID!])
Epic.children(iid: ID)
Epic.children(iids: [ID!])
Epic.ancestors(iid: ID)
Epic.ancestors(iids: [ID!])
Epic.children(iid: ID)
Epic.children(iids: [ID!])
Epic.ancestors(iid: ID)
Epic.ancestors(iids: [ID!])
GeoNode.mergeRequestDiffRegistries(ids: [ID!])
GeoNode.packageFileRegistries(ids: [ID!])
GeoNode.snippetRepositoryRegistries(ids: [ID!])
GeoNode.terraformStateVersionRegistries(ids: [ID!])
GeoNode.groupWikiRepositoryRegistries(ids: [ID!])
GeoNode.lfsObjectRegistries(ids: [ID!])
GeoNode.pipelineArtifactRegistries(ids: [ID!])
GeoNode.pagesDeploymentRegistries(ids: [ID!])
GeoNode.uploadRegistries(ids: [ID!])
InstanceSecurityDashboard.vulnerabilitySeveritiesCount(projectId: [ID!])

Currently we support values for these arguments being supplied as ID, which is a non-standard extension to the GraphQL validation logic. This will become a validation error.

Instead of:

query($id: ID!) {
  issue(id: $id) { title }
}

You should write this query as:

query($id: IssueID!) {
  issue(id: $id) { title }
}

or use an inline argument expression:

query {
  issue(id: "gid://gitlab/Issue/71807251") { title }
}

If you encounter this breaking change, you will see a validation error in the response similar to:

{
  "errors": [
    {
      "message": "Type mismatch on variable $id and argument id (ID! / IssueID!)",
      "locations": [
        {
          "line": 2,
          "column": 9
        }
      ],
      "path": [
        "query",
        "issue",
        "id"
      ],
      "extensions": {
        "code": "variableMismatch",
        "variableName": "id",
        "typeName": "ID!",
        "argumentName": "id",
        "errorMessage": "Type mismatch"
      }
    }
  ]
}

Affected Topology

All deployments are affected by this change.

Affected Tier

GraphQL is available in the Free tier.

Checklist

  • @mention your stage's stable counterparts on this issue. For example, Customer Support, Customer Success (Technical Account Manager), Product Marketing Manager.

    • To see who the stable counterparts are for a product team visit product categories
      • If there is no stable counterpart listed for Sales/CS please mention @timtams
      • If there is no stable counterpart listed for Support please mention @gitlab-com/support/managers
      • If there is no stable counterpart listed for Marketing please mention @cfoster3
  • @mention your GPM so that they are aware of planned deprecations. The goal is to have reviews happen at least two releases before the final removal of the feature or introduction of a breaking change.

Deprecation Milestone

%14.8

Planned Removal Milestone

%15.0

Links

All developers should use the GraphQL reference documentation and schemas to help write valid queries:

Users are encouraged to make use of the GraphQL explorer to build and validate queries:

The GraphQL explorer only permits use of the standards-compliant queries, so users will be able to test any queries they use for validity.

Edited by Alex Kalderimis