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
type Query { user(id: ID!): User users(role: UserRole, limit: Int = 10): [User!]!}
Client query
{ user(id: "UHJvZHVjdAppMQ==") { name }}
Arguments are frequently provided through variables, which separate the static query structure from the dynamic runtime values:
query ($userId: ID!) { user(id: $userId) { name }}
Defining Arguments
Method parameters on a resolver become GraphQL arguments.
[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.
Renaming Arguments
Use [GraphQLName] to change the argument name in the schema while keeping the C# parameter name unchanged.
[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.
[QueryType]public static partial class ProductQueries{ public static List<Product> GetProducts(string? category, int? limit) { // Both arguments are optional // ... }}
This produces:
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.
[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:
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:
[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.
[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):
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.
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:
input BookFilterInput { title: String author: String year: Int}
type Query { books(filter: BookFilterInput!): [Book!]!}
Next Steps
- Need structured input? See Input Object Types.
- Need to understand nullability? See Non-Null.
- Need global IDs? See Relay.
- Need to set up resolvers? See Resolvers.