Is your feature request related to a problem? Please describe.
If I want to write Mutations according to the relay guide I have to declare an input type containing all arguments and a clientMutationId which is returned in the response.
Currently I have to write a lot of annoying Code. One class for the input, one for the payload and in the Mutation itself I have to pass the clientMutationId from the input to the payload manually.
Describe the solution you'd like
I would like to have a very simple and easy solution to speed up development. Maybe something like:
In my mutation/Resolver i would like to have a function as always without the inputType:
public User CreateUser(string firstname, string lastname, CancellationToken ctx){
...
return new User(....);
}
in my ObjectType for the Muation I would like to do something like:
descriptor
.Field(m => m.CreateUser(default, default, default))
.UseRelayInputType()
this than should convert this stuff to provide a schema like:
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
type CreateUserInput{
fistname: String
lastname: String
clientMutationId: String
}
type CreateUserPayload{
user: User
clientMutationId: String
}
HC should then automatically pass the `clientMutationId``from the input to the payload and all the fields should be mapped. The GraphQLNonNullType should be respected by this solution
I thought about this one on the way back home and I think it is quite easy to implement with the new V9 type system. I think it is about 2 hours of work with testing. If you want to do this one I can show you how to implement this.
Any updates on this?
Perhaps if Hot Chocolate included a RelayInputObjectType<T> base class with the clientMutationId field pre-configured on it, this could be used instead of InputObjectType<T>.
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
type CreateUserInput{
fistname: String
lastname: String
clientMutationId: String!
}
// Base class for CreateUserInput
public abstract class RelayInputObject<TObjectType> : InputObjectType<TObjectType>
where TObjectType : InputObjectType
{
protected override void Configure(IInputObjectTypeDescriptor<TObjectType> descriptor)
{
descriptor
.Field("clientMutationId")
.Type<NonNullType<StringType>>()
.Description("The unique identifier of the mutation, sent from the client.");
}
}
Then for the output, a RelayOutputObjectType<T> class could look something like this:
type RelayOutput{
value: Foo
clientMutationId: String
}
public class RelayOutputObject<TObjectType> : ObjectType<TObjectType>
where TObjectType : ObjectType
{
protected override void Configure(IObjectTypeDescriptor<TObjectType> descriptor)
{
if (descriptor is null)
{
throw new ArgumentNullException(nameof(descriptor));
}
descriptor.Name("RelayOutput");
descriptor.Description("The output of a mutation, containing the value and .");
descriptor
.Field("value")
.Type<TObjectType>()
.Description("The value of the mutation output.");
descriptor
.Field("clientMutationId")
.Type<NonNullType<StringType>>()
.Description("The unique identifier of the mutation, sent from the client.");
}
}
If Hot Chocolate, knows about both of these types, it could connect the dots and pass the parameter automatically, via some middleware.
We are getting ready for an 11 release and this one is now move to the December patch release of 11.
Most helpful comment
I thought about this one on the way back home and I think it is quite easy to implement with the new V9 type system. I think it is about 2 hours of work with testing. If you want to do this one I can show you how to implement this.