GraphQL with ASP.NET Core (Part- V : Fields, Arguments, Variables)

微信扫一扫,分享到朋友圈

GraphQL with ASP.NET Core (Part- V : Fields, Arguments, Variables)

Read the previous part – GraphQL with ASP.NET Core (Part- IV : GraphiQL – An in-browser IDE)

Fields

We already have a good idea of GraphQL Fields . Remember we had two fields under the HelloWorldQuery i.e. hello and howdy . Both of them were scaler fields. 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 an Inventory system. Start by creating an Item type,

public class Item  
{
    public string Barcode { get; set; }

    public string Title { get; set; }

    public decimal SellingPrice { get; set; }
}

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 flavor of ObjectGraphType takes generic types. As you already guessed it, we will pass the Item type as its generic argument.

public class ItemType : ObjectGraphType  
{
    public ItemType()
    {
        Field(i => i.Barcode);
        Field(i => i.Title);
        Field(i => i.SellingPrice);
    }
}

Two things to notice down here. First, we no longer have type declarations in the fields. It will automatically get resolved by the library i.e. dot net string type will be resolved to StringGraphType . Second, we used lambda expressions to 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. HelloWorldQuery ,

public HelloWorldQuery()  
{
    ...
    ...

    Field(
        "item",
        resolve: context =>
        {
           return new Item {
                Barcode = "123",
                Title = "Headphone",
                SellingPrice = 12.99M
            };
        }
    ); 
}

For the time being, we are returning a hard-coded instance of Item when someone tries to query the item field. 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,

public class DataSource  
{
    public IList Items
    {
        get;
        set;
    }

    public DataSource()
    {
        Items = new List(){
            new Item { Barcode= "123", Title="Headphone", SellingPrice=50},
            new Item { Barcode= "456", Title="Keyboard", SellingPrice= 40},
            new Item { Barcode= "789", Title="Monitor", SellingPrice= 100}
        };
    }

    public Item GetItemByBarcode(string barcode)
    {
        return Items.First(i => i.Barcode.Equals(barcode));
    }
}

Along with the Items collection, we also have a method returns a single item that matches the a passed in barcode string.

Great! Now to pass in an argument via the query we have to modify the item field as followings,

Field(
    "item",
    arguments: new QueryArguments(new QueryArgument { Name = "barcode" }),
    resolve: context =>
    {
        var barcode = context.GetArgument("barcode");
        return new DataSource().GetItemByBarcode(barcode);
    }
);

There could be a list of arguments; some required and some optional. We specify an individual argument and its type with the QueryArgument . The Name represents the name of the argument.

Now, we can construct a query inside GraphiQL with pre-defined arguments as followings,

query {  
  item (barcode: "123") {
    title
    selling price
  }
}

At this point, the barcode argument is optional. So, if you do something like below,

query {  
  item {
    title
    sellingPrice
  }
}

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 nonnullable with the following syntax,

QueryArgument<NonNullGraphType> { Name = "barcode" }

So, if we try to execute the same query in GraphiQL , it will give you nice error message as followings,

Variables

It’s time to make the argument itself dynamic. We dont want to construct a whole query wherever 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.

public class GraphQLRequest
{
    public string Query { get; set; }
    public JObject Variables { get; set; }
}

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($barcode: String!){  
  item(barcode: $barcode){
    title
    sellingPrice
  }
}

Variable definitation 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 vaiable is non-nullable. Hence we used a ! mark after the String type.

To use the variable to send data we have a Query Variables pane inside GraphiQL . Use it to configure variables as followings,

Repository Link (Branch)

Part V

得女性者得天下?18年,优酷用“女生季”打响了女性市场的第一战

上一篇

A tech company is giving each employee $1,500 to spend on experiences — and it's a millenni...

下一篇

你也可能喜欢

GraphQL with ASP.NET Core (Part- V : Fields, Arguments, Variables)

长按储存图像,分享给朋友