Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Treat [Required] arguments like ArgumentHelper.Required<T>(), bump to…
… 6.3.0

[Required] marked the argument non-null but kept a value type's implicit
default(T) as the schema default, so `[Required] int Take` printed
`take: Int! = 0` and a query leaving it out ran with 0. Clear the default
for [Required] the same way RequiredField<> already does, so the argument
must be supplied.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
  • Loading branch information
lukemurray and claude committed Sep 29, 2026
commit c46215c728a25d702e4d997696fafe736627b00b
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# 6.2.5
# 6.3.0

## Changes

- `[Required]` on an argument (a property/field of an arguments object or a method parameter) now behaves like `ArgumentHelper.Required<T>()` - the argument has no default value and must be provided by the query. Previously a value type kept its implicit `default(T)` as the schema default, so `[Required] int Take` printed `take: Int! = 0` (optional for clients) and a query leaving it out ran with `0`. It is now `take: Int!` and leaving it out is a `missing required argument` error. Remove `[Required]` if you relied on the old default.

## Fixes

Expand Down
10 changes: 10 additions & 0 deletions docs/docs/schema-creation/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ It is worth noting that the GraphQL name of the argument will be that of the pro

As you see above to make an argument required use the `ArgumentHelper.Required<T>()` method.

If you use a class for your arguments, mark the property with `[Required]` instead. Either way the argument has no default value in the schema and the query must supply it - otherwise a value type property like `int Take` gets its C# default as the schema default (`take: Int! = 0`).

```cs
public class PersonArgs
{
[Required]
public int Id { get; set; }
}
```

See [Validation](../validation) for further information.

### Optional arguments
Expand Down
2 changes: 1 addition & 1 deletion src/EntityGraphQL.AspNet/EntityGraphQL.AspNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AssemblyName>EntityGraphQL.AspNet</AssemblyName>
<PackageId>EntityGraphQL.AspNet</PackageId>
<LangVersion>14</LangVersion>
<PackageVersion>6.2.5</PackageVersion>
<PackageVersion>6.3.0</PackageVersion>
<Description>Contains ASP.NET extensions and middleware for EntityGraphQL</Description>
<Authors>Luke Murray</Authors>
<PackageProjectUrl>https://github.com/lukemurray/EntityGraphQL</PackageProjectUrl>
Expand Down
2 changes: 1 addition & 1 deletion src/EntityGraphQL/EntityGraphQL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<LangVersion>14.0</LangVersion>
<AssemblyName>EntityGraphQL</AssemblyName>
<PackageId>EntityGraphQL</PackageId>
<PackageVersion>6.2.5</PackageVersion>
<PackageVersion>6.3.0</PackageVersion>
<Description>A GraphQL library for .NET. Compiles queries into .NET Expressions (LinqProvider) for runtime execution against object graphs. E.g. against an ORM data model (EntityFramework or others) or just an in-memory object.</Description>
<Authors>Luke Murray</Authors>
<PackageProjectUrl>https://github.com/lukemurray/EntityGraphQL</PackageProjectUrl>
Expand Down
6 changes: 5 additions & 1 deletion src/EntityGraphQL/Schema/ArgType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ NullabilityInfo nullability
{
markedRequired = true;
argType = gqlLookupType = gqlLookupType.GetGenericArguments()[0];
}
var requiredAttribute = attributes.FirstOrDefault(a => a is RequiredAttribute) as RequiredAttribute;
if (markedRequired || requiredAttribute != null)
{
// default value will often be the default value of the non-null type (e.g. 0 for int).
// We are saying here it must be provided by the query
defaultValue.Value = null;
Expand All @@ -118,7 +122,7 @@ NullabilityInfo nullability
{
DefaultValue = defaultValue,
IsRequired = markedRequired,
requiredAttribute = attributes.FirstOrDefault(a => a is RequiredAttribute) as RequiredAttribute,
requiredAttribute = requiredAttribute,
};

if (memberInfo?.GetCustomAttribute<GraphQLFieldAttribute>() is GraphQLFieldAttribute gqlFieldAttr)
Expand Down
35 changes: 35 additions & 0 deletions src/tests/EntityGraphQL.Tests/QueryTests/ArgumentTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using EntityGraphQL.Compiler;
using EntityGraphQL.Extensions;
Expand Down Expand Up @@ -117,6 +118,40 @@ public void ThrowsOnMissingRequiredArguments()
Assert.Equal("Field 'user' - missing required argument 'id'", result.Errors[0].Message);
}

private class RequiredAttributeArgs
{
[Required]
public int Id { get; set; }

[Required]
public Guid RunId { get; set; }

public int Plain { get; set; }
}

[Fact]
public void RequiredAttributeValueTypeHasNoDefault()
{
var schema = SchemaBuilder.FromObject<TestDataContext>(new SchemaBuilderOptions { AutoCreateFieldWithIdArguments = false });
schema.Query().AddField("user", new RequiredAttributeArgs(), (ctx, param) => ctx.Users.FirstOrDefault(u => u.Id == param.Id), "Return a user by ID");

Assert.Contains("user(id: Int!, runId: ID!, plain: Int! = 0): User", schema.ToGraphQLSchemaString());

var result = schema.ExecuteRequestWithContext(new QueryRequest { Query = "{ user { id } }" }, new TestDataContext(), null, null);
Assert.NotNull(result.Errors);
Assert.Contains(result.Errors, e => e.Message == "Field 'user' - missing required argument 'id'");
Assert.Contains(result.Errors, e => e.Message == "Field 'user' - missing required argument 'runId'");

result = schema.ExecuteRequestWithContext(
new QueryRequest { Query = "{ user(id: 100, runId: \"00000000-0000-0000-0000-000000000001\") { id } }" },
new TestDataContext().FillWithTestData(),
null,
null
);
Assert.Null(result.Errors);
Assert.Equal(100, ((dynamic)result.Data!["user"]!).id);
}

[Fact]
public void SupportsArgumentsDefaultValue()
{
Expand Down
Loading