Back to Graphql Platform

Arguments

website/src/docs/hotchocolate/v16/building-a-schema/arguments.md

16.1.0-p.1.105.1 KB
Original Source

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.

<ExampleTabs> <Implementation>
csharp
// Types/UserQueries.cs
[QueryType]
public static partial class UserQueries
{
    public static User? GetUser(string username, UserService users)
        => users.FindByName(username);
}

The username parameter becomes a username: String! argument. The UserService parameter is recognized as a service and is not exposed in the schema.

</Implementation> <Code>
csharp
// Types/UserQueriesType.cs
public class UserQueriesType : ObjectType
{
    protected override void Configure(IObjectTypeDescriptor descriptor)
    {
        descriptor.Name(OperationTypeNames.Query);

        descriptor
            .Field("user")
            .Argument("username", a => a.Type<NonNullType<StringType>>())
            .Resolve(context =>
            {
                var username = context.ArgumentValue<string>("username");
                // ...
            });
    }
}
</Code> </ExampleTabs>

Renaming Arguments

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

csharp
// Types/UserQueries.cs
[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.

csharp
// Types/ProductQueries.cs
[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.

csharp
// Types/ProductQueries.cs
[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:

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

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.

csharp
// Types/ProductQueries.cs
[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):

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

In v16, 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.

csharp
// Types/BookFilterInput.cs
public record BookFilterInput(string? Title, string? Author, int? Year);

// Types/BookQueries.cs
[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