Skip to content

Commit

Permalink
Allow reading ids containing integers as strings (graphql-dotnet#4076)
Browse files Browse the repository at this point in the history
Allow coercing ids to strings
  • Loading branch information
Shane32 authored Oct 5, 2024
1 parent 2af9f60 commit 927ff77
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 25 deletions.
49 changes: 24 additions & 25 deletions src/GraphQL.Tests/Bugs/Bug1046.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,38 @@ public async Task any_registration_order_should_work(bool order)
});
response.Data.ShouldNotBeNull();
}
}

public class QueryGraphType : ObjectGraphType
{
public QueryGraphType()
public class QueryGraphType : ObjectGraphType
{
Field<InterfaceGraphType>("inst").Resolve(_ => new Implementation());
public QueryGraphType()
{
Field<InterfaceGraphType>("inst").Resolve(_ => new Implementation());
}
}
}

public interface IInterface
{
string Id { get; }
}
public interface IInterface
{
string Id { get; }
}

public class InterfaceGraphType : InterfaceGraphType<IInterface>
{
public InterfaceGraphType()
public class InterfaceGraphType : InterfaceGraphType<IInterface>
{
Field(i => i.Id);
public InterfaceGraphType()
{
Field(i => i.Id);
}
}
}

public class Implementation : IInterface
{
public string Id => "Data!";
}
public class Implementation : IInterface
{
public string Id => "Data!";
}

public class ImplementationGraphType : ObjectGraphType<Implementation>
{
public ImplementationGraphType()
public class ImplementationGraphType : ObjectGraphType<Implementation>
{
Field(i => i.Id);
Interface<InterfaceGraphType>();
public ImplementationGraphType()
{
Field(i => i.Id);
Interface<InterfaceGraphType>();
}
}
}
63 changes: 63 additions & 0 deletions src/GraphQL.Tests/Bugs/Issue4075.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Numerics;
using GraphQL.Types;

namespace GraphQL.Tests.Bugs.Bug1046;

public class Issue4075
{
[Fact]
public async Task id_should_be_readable_as_string_or_integer()
{
// this test ensures that an ID, passed as either a string or integer, can be read as either type
// note that Apollo Router coerces IDs that are strings containing only digits to integers, so this is a common scenario
// even when the client sends IDs as strings

var schema = new Schema { Query = new QueryGraphType() };

var response = await schema.ExecuteAsync(_ =>
{
_.Query = """
query q($idStr: ID!, $idInt: ID!, $largeInt: ID!, $veryLargeInt: ID!) {
string1: string(arg: $idStr)
int1: int(arg: $idStr)
string2: string(arg: $idInt)
int2: int(arg: $idInt)
largeInt: string(arg: $largeInt)
veryLargeInt: string(arg: $veryLargeInt)
}
""";
_.Variables = new Dictionary<string, object?> {
{ "idStr", "123" },
{ "idInt", 123 },
{ "largeInt", 123456789012345678L },
{ "veryLargeInt", BigInteger.Parse("123456789012345678901234567890") },
}.ToInputs();
});

response.ShouldBeCrossPlatJson("""
{
"data": {
"string1": "123",
"int1": 123,
"string2": "123",
"int2": 123,
"largeInt": "123456789012345678",
"veryLargeInt": "123456789012345678901234567890"
}
}
""");
}

public class QueryGraphType : ObjectGraphType
{
public QueryGraphType()
{
Field<NonNullGraphType<StringGraphType>>("string")
.Argument<NonNullGraphType<IdGraphType>>("arg")
.Resolve(ctx => ctx.GetArgument<string>("arg"));
Field<NonNullGraphType<IntGraphType>>("int")
.Argument<NonNullGraphType<IdGraphType>>("arg")
.Resolve(ctx => ctx.GetArgument<int>("arg"));
}
}
}
3 changes: 3 additions & 0 deletions src/GraphQL/Conversion/ValueConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static ValueConverter()
Register<int, float>(value => value);
Register<int, decimal>(value => value);
Register<int, TimeSpan>(value => TimeSpan.FromSeconds(value));
Register<int, string>(value => value.ToString(CultureInfo.InvariantCulture));

Register<long, sbyte>(value => checked((sbyte)value));
Register<long, byte>(value => checked((byte)value));
Expand All @@ -88,6 +89,7 @@ static ValueConverter()
Register<long, float>(value => value);
Register<long, decimal>(value => value);
Register<long, TimeSpan>(value => TimeSpan.FromSeconds(value));
Register<long, string>(value => value.ToString(CultureInfo.InvariantCulture));

Register<BigInteger, sbyte>(value => checked((sbyte)value));
Register<BigInteger, byte>(value => checked((byte)value));
Expand All @@ -101,6 +103,7 @@ static ValueConverter()
Register<BigInteger, ulong>(value => checked((ulong)value));
Register<BigInteger, int>(value => checked((int)value));
Register<BigInteger, float>(value => checked((float)value));
Register<BigInteger, string>(value => value.ToString(CultureInfo.InvariantCulture));

Register<uint, sbyte>(value => checked((sbyte)value));
Register<uint, byte>(value => checked((byte)value));
Expand Down

0 comments on commit 927ff77

Please sign in to comment.