GraphQL with .NET Core (Part - V: Fields, Arguments, Variables)
Code samples used in this blog series have been updated to latest version of .NET Core (5.0.4) and GraphQL-Dotnet (4.2.0). Follow this link to get the updated samples.
Fields
We already have a good idea of GraphQL Fields
. Remember we have a field under the GameStoreQuery
i.e. name
,
It's a simple scaler field. However, we can work with complex types as well; as the official documentation states,
"At its simplest, GraphQL is about asking for specific fields on objects" - graphql.org
Let's extend our simple application to accommodate a complex type. Say, for example, we are heading towards a path of making a Digital Distribution Service (DDS) platform like Steam
or GOG
. Start by creating an Item
type,
However, we can't directly query against this object as it is not a GraphQL
object i.e. not an ObjectGraphType
. To make it GraphQL
queryable, we should create a new type and extend it from ObjectGraphType
.
Another flavour of ObjectGraphType
takes generic types. As you already guessed it, we will pass the Item
type as its generic argument.
Two things to notice down here. First, we no longer have type declarations in the fields. They will automatically get resolved by the library i.e. dot net string
type will be resolved to StringGraphType
. Second, we used lambda
expressions to map properties and resolve things like the name of the fields
. This concept of property matching should be easy to understand for the people who are familiar with the notion of DTOs/ViewModels
. So, whoever thinks that we are dealing with an extra burden of type creation; trust me, we are not!
Next, we need to register the ItemType
in our root query object i.e. GameStoreQuery
,
For the time being, we are returning a hard-coded instance of Item
when someone tries to query the item
field. Finally we have to wire up this new type with the DI container,
We can run our application now and do the following,
Arguments
Serving a hard-coded instance is not going to cut it. How about we introduce a data source which will serve the purpose of giving away a list of items,
Along with the Items
collection, we also have a method which returns a single item that matches a passed in tag
string.
Great! Now to pass in an argument via the query we have to modify the item
field as followings,
There could be a list of arguments; some required and some optional. We specify an individual argument and its type with the QueryArgument<T>
. The Name
represents the name of an individual argument.
Now, we can construct a query inside GraphiQL
with pre-defined arguments as followings,
query GameByTagQuery {
item(tag: "cyberpunk_2077") {
title
price
}
}
At this point, the barcode argument is optional. So, if you do something like below,
query {
item {
title
price
}
}
It will throw an error saying Error trying to resolve item
.
That's fair since we didn't really write our code in a safe way. To ensure that user always provides an argument we can make the argument non-nullable with the following syntax,
QueryArgument<NonNullGraphType<StringGraphType>> { Name = "tag" }
So, if we try to execute the same query in GraphiQL
, it will give you a nice error message as followings,
Variables
It's time to make the argument itself dynamic. We don't want to construct a whole query whenever we want to change a value of an argument, do we? Hence come variables. But first, we have to make sure our GraphQL
middleware accepts variables. Go back to the GraphQLRequest
class and add a Variables
property.
Notice, we have a new import GraphQL.SystemTextJson
. Install this package from the GraphQL Dotnet
personal package source,
dotnet add package GraphQL.SystemTextJson -v 3.0.0-preview-1650 -s https://www.myget.org/F/graphql-dotnet/api/v3/index.json
Next find out the _executor.ExecuteAsync
method in the middleware's InvokeAsync
method and modify as followings,
var result = await _executor.ExecuteAsync(doc =>
{
doc.Schema = _schema;
doc.Query = request.Query;
doc.Inputs = request.Variables.ToInputs();
}).ConfigureAwait(false);
Nice! our query is now ready to accept variables. Run the application and write a query as followings,
query($tag: String!){
item(tag: $tag){
title
price
}
}
Variable definition starts with a $
sign, followed by the variable type. Since we made the barcode
argument non-nullable, here we also have to make sure the variable is non-nullable. Hence we used a !
mark after the String
type.
To use the variable to transfer data we have a Query Variables
pane inside GraphiQL
. Use it to configure required variables as followings,
Repository Link
Important Links
Create Data Transfer Objects (DTOs)