Arguments

GraphQL arguments let clients pass values to individual fields. In Hot Chocolate, each parameter on a resolver method becomes a field argument in the schema, unless it is a recognized service type (like CancellationToken or a registered service).

GraphQL schema

GraphQL
type Query {
  user(id: ID!): User
  users(role: UserRole, limit: Int = 10): [User!]!
}

Client query

GraphQL
{
  user(id: "UHJvZHVjdAppMQ==") {
    name
  }
}

Arguments are frequently provided through variables, which separate the static query structure from the dynamic runtime values:

GraphQL
query ($userId: ID!) {
  user(id: $userId) {
    name
  }
}

Defining Arguments#

Method parameters on a resolver become GraphQL arguments.

Renaming Arguments#

Use [GraphQLName] to change the argument name in the schema while keeping the C# parameter name unchanged.

C#
[QueryType]
public static partial class UserQueries
{
    public static User? GetUser(
        [GraphQLName("name")] string username,
        UserService users)
        => users.FindByName(username);
}

This produces user(name: String!): User in the schema.

Optional Arguments#

An argument is required when its C# type is non-nullable. Make an argument optional by using a nullable type.

C#
[QueryType]
public static partial class ProductQueries
{
    public static List<Product> GetProducts(string? category, int? limit)
    {
        // Both arguments are optional
        // ...
    }
}

This produces:

GraphQL
type Query {
  products(category: String, limit: Int): [Product!]!
}

When using nullable reference types (recommended), string maps to String! and string? maps to String. See Non-Null for details.

Default Values#

Use [DefaultValue] to assign a default to an argument. The default appears in the schema and is used when the client omits the argument.

C#
[QueryType]
public static partial class ProductQueries
{
    public static List<Product> GetProducts(
        [DefaultValue(10)] int limit)
    {
        // ...
    }
}

This produces products(limit: Int! = 10): [Product!]!.

C# default parameter values also work:

C#
public static List<Product> GetProducts(int limit = 10)

For complex default values that cannot be expressed as C# constants (such as input objects), use [DefaultValueSyntax] with GraphQL value syntax:

C#
[QueryType]
public static partial class ProductQueries
{
    public static List<Product> GetProducts(
        [DefaultValueSyntax("{ title: null, year: 2024 }")] BookFilterInput filter)
    {
        // ...
    }
}

This produces products(filter: BookFilterInput! = { title: null, year: 2024 }): [Product!]!. The string is parsed as a GraphQL value literal at schema build time.

The ID Attribute#

The [ID] attribute marks a parameter as a GraphQL ID scalar. When combined with global object identification, it also deserializes the opaque global ID back to the underlying value.

C#
[QueryType]
public static partial class ProductQueries
{
    public static Product? GetProduct([ID] int id, CatalogContext db)
        => db.Products.Find(id);
}

To restrict the ID to a specific type (ensuring only IDs serialized for Product are accepted):

C#
public static Product? GetProduct(
    [ID(nameof(Product))] int id,
    CatalogContext db)
    => db.Products.Find(id);

You can also use the generic form [ID<Product>] which infers the type name automatically.

Complex Arguments#

When an argument needs multiple fields, use an input object type instead of multiple scalar arguments.

C#
public record BookFilterInput(string? Title, string? Author, int? Year);

[QueryType]
public static partial class BookQueries
{
    public static List<Book> GetBooks(BookFilterInput filter, CatalogContext db)
    {
        // ...
    }
}

This produces:

GraphQL
input BookFilterInput {
  title: String
  author: String
  year: Int
}

type Query {
  books(filter: BookFilterInput!): [Book!]!
}

Next Steps#

Edit this page on GitHub
Last updated on by Tobias Tengler