正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

GraphQL Array Arguments

一貫した開発プロセスとドキュメントを確保するため、GitLabへのすべての貢献は英語で提出する必要があります。そのため、GitLabへの貢献に関するドキュメント(https://docs.gitlab.com/development/に掲載)も英語でのみ提供されています。

以下を希望される場合:

  • コードの貢献を提出する
  • バグの報告または修正
  • 機能や改善の提案
  • ドキュメントへの貢献

これらのページの英語版のガイドラインに従ってください。

このページの英語版にアクセスしてください。

Array Argument Validation in GraphQL

Overview

All array arguments in GitLab GraphQL API should have size validation to prevent abuse and performance issues.

Validation Approaches

Use the validates option to explicitly declare array size limits:

argument :assignee_usernames, [GraphQL::Types::String],
  required: false,
  validates: { length: { maximum: Types::BaseArgument::MAX_ARRAY_SIZE } },
  description: "Usernames of users assigned to the merge request " \
    "(maximum is #{Types::BaseArgument::MAX_ARRAY_SIZE} usernames)."

Benefits:

  • Clear and explicit
  • Visible in the argument definition
  • Consistent with existing codebase patterns
  • Uses GraphQL-Ruby’s built-in validation

Automatic Validation (Transition Period)

During the transition period, array arguments without explicit validates: { length: { maximum: ... } } will automatically be limited to 100 items by BaseArgument.

# This will automatically be limited to 100 items
argument :items, [GraphQL::Types::String],
  required: false,
  description: 'List of items.'

How It Works

The BaseArgument class implements smart detection:

  1. If explicit validation exists: Uses the explicit limit (no automatic validation)
  2. If no explicit validation: Applies automatic 100-item limit
# Explicit validation - uses 50 as the limit
argument :limited_items, [GraphQL::Types::String],
  validates: { length: { maximum: 50 } },
  description: 'Limited to 50 items.'

# No explicit validation - automatically limited to 100 items
argument :auto_limited_items, [GraphQL::Types::String],
  description: 'Automatically limited to 100 items.'

Migration Path

Step 1: Automatic Protection (Current)

All array arguments are automatically protected with a 100-item limit.

Step 2: Add Explicit Validation

Gradually add explicit validates declarations to all array arguments:

# Before (relies on automatic validation)
argument :assignee_usernames, [GraphQL::Types::String],
  required: false,
  description: 'Usernames of users assigned to the merge request.'

# After (explicit validation)
argument :assignee_usernames, [GraphQL::Types::String],
  required: false,
  validates: { length: { maximum: Types::BaseArgument::MAX_ARRAY_SIZE } },
  description: "Usernames of users assigned to the merge request " \
    "(maximum is #{Types::BaseArgument::MAX_ARRAY_SIZE} usernames)."

Step 3: Remove Automatic Validation

Once all array arguments have explicit validation, we can remove the automatic validation from BaseArgument.

Constants

Types::BaseArgument::MAX_ARRAY_SIZE

Default maximum size for array arguments (currently 100).

Use this constant for consistency:

validates: { length: { maximum: Types::BaseArgument::MAX_ARRAY_SIZE } }

Custom Limits

For specific use cases, you can use a different limit:

# Using a module constant
module WorkItems
  module SharedFilterArguments
    MAX_FIELD_LIMIT = 100
  end
end

argument :ids, [::Types::GlobalIDType[::WorkItem]],
  validates: { length: { maximum: WorkItems::SharedFilterArguments::MAX_FIELD_LIMIT } },
  description: "Filter by global IDs (maximum is #{WorkItems::SharedFilterArguments::MAX_FIELD_LIMIT} IDs)."

Error Messages

When validation fails, users receive a clear error message:

"assigneeUsernames cannot accept more than 100 items"

Examples

Good Examples

# Example 1: Using the default constant
argument :user_ids, [GraphQL::Types::ID],
  validates: { length: { maximum: Types::BaseArgument::MAX_ARRAY_SIZE } },
  description: "User IDs (maximum is #{Types::BaseArgument::MAX_ARRAY_SIZE})."

# Example 2: Using a custom constant
argument :label_names, [GraphQL::Types::String],
  validates: { length: { maximum: WorkItems::SharedFilterArguments::MAX_FIELD_LIMIT } },
  description: "Label names (maximum is #{WorkItems::SharedFilterArguments::MAX_FIELD_LIMIT})."

# Example 3: Custom limit for specific use case
argument :vulnerability_ids, [GraphQL::Types::ID],
  validates: { length: { minimum: 1, maximum: 50 } },
  description: "Vulnerability IDs (minimum 1, maximum 50)."

Bad Examples

# Bad: No validation and no description of limit
argument :items, [GraphQL::Types::String],
  description: 'List of items.'

# Bad: Hardcoded number without constant
argument :items, [GraphQL::Types::String],
  validates: { length: { maximum: 100 } },
  description: 'List of items (maximum is 100).'

Testing

When testing resolvers or mutations with array arguments, test the validation:

RSpec.describe Resolvers::MyResolver do
  it 'accepts arrays within the limit' do
    items = Array.new(50, 'item')
    expect { resolve(items: items) }.not_to raise_error
  end

  it 'rejects arrays exceeding the limit' do
    items = Array.new(101, 'item')
    expect { resolve(items: items) }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
  end
end