1. 程式人生 > >ASP.NET Core中使用GraphQL - 第五章 欄位, 引數, 變數

ASP.NET Core中使用GraphQL - 第五章 欄位, 引數, 變數

ASP.NET Core中使用GraphQL


欄位

我們已經很好的理解了GraphQL中的欄位。在之前HelloWorldQuery的例子中,我們添加了2個欄位hellohowdy. 它們都是標量欄位。正如GraphQL官網文件中宣告的那樣

"At its simplest, GraphQL is about asking for specific fields on objects"

簡單來說,GraphQL就是詢問物件中的一些特定欄位

來源: graphql.org

下面我們來為我們的例項程式新增一些複雜的型別。比如,現在我們需要編寫一個庫存系統,我們首先新增一個貨物類Item, 其程式碼如下:

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

    public string Title { get; set; }

    public decimal SellingPrice { get; set; }
}

但是我們不希望直接針對這個物件建立查詢,因為它不是一個GraphQL

物件,它沒有繼承自ObjectGraphType, 為了建立一個GraphQL查詢,我們需要建立一個新類ItemType, 它繼承自ObjectGraphType類。

另外ObjectGraphType類是一個泛型類,所以這裡我們需要指定它的泛型引數是Item

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

這裡有2點需要注意。首先我們不在針對欄位進行型別聲明瞭。GraphQL庫將實體類屬性欄位型別對映成GraphQL的內建型別。例如這裡Barcode的型別string會被對映成GraphQL的內建型別StringGraphType。其次這裡我們使用了Lambda表示式設定了實體類屬性和GraphQL欄位之間的對映, 這有點類似於資料庫模型和ViewModel之間的轉換的對映。

下一步,我們需要在HelloWorldQuery中註冊ItemType

public HelloWorldQuery()  
{
    ...
    ...

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

這裡我們暫時設定了一個硬編碼的返回值。所以當查詢item物件的時候,這個硬編碼的返回值會輸出出來。

現在我們啟動專案,進入GraphiQL介面

首先我們設定查詢為

query {
    item{
        barcode
        sellingPrice
    }
}

執行查詢之後,結果是

{
  "data": {
    "item": {
      "barcode": "123",
      "sellingPrice": 12.99
    }
  }
}

然後我們修改查詢為

query {
    item{
        barcode
        sellingPrice
        title
    }
}

執行查詢之後,結果是

{
  "data": {
    "item": {
      "barcode": "123",
      "sellingPrice": 12.99,
      "title": "Headphone"
    }
  }
}

這說明我們的GraphQL查詢已經生效,api根據我們需要的欄位返回了正確的返回值。

引數

這裡我們可以使用引數去除前面的硬編碼。

為了說明如何使用引數,這裡我們首先建立一個數據源類DataSource, 其程式碼如下

public class DataSource  
{
    public IList<Item> Items
    {
        get;
        set;
    }

    public DataSource()
    {
        Items = new List<Item>(){
            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));
    }
}

這裡除了Items集合,我們還添加了一個方法GetItemByBarcode, 這個方法可以根據傳遞的barcode引數返回第一個匹配的Item

然後現在我們來修改之前的item查詢, 新增一個arguments引數, 其程式碼如下:

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

arguments是一個引數列表,裡面可以包含必填引數和選填引數。針對每個引數,我們都需要指定它對應的型別,這裡Name屬性是設定了當前引數的名稱。

resolve引數中, 你可以使用context.GetArgument () 方法獲取查詢中傳遞的引數值。

現在我們重新啟動專案,並在GraphiQL中新增如下查詢

query {  
  item (barcode: "123") {
    title
    sellingPrice
  }
}

輸出的查詢結果

{
  "data": {
    "item": {
      "title": "Headphone",
      "sellingPrice": 50
    }
  }
}

這個結果與我們預想的一樣。

但是這時候如果我們不傳遞barcode引數

query {  
  item {
    title
    sellingPrice
  }
}

程式就會報錯

{
  "data": {
    "item": null
  },
  "errors": [
    {
      "message": "Error trying to resolve item.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "item"
      ],
      "extensions": {
        "code": "INVALID_OPERATION"
      }
    }
  ]
}

原因是當前barcode是一個可空項,程式查詢時, First方法會報錯。所以這時候我們可以使用NonNullGraphType 來設定barcode為一個必填項。

QueryArgument<NonNullGraphType<StringGraphType>> { Name = "barcode" }  

這樣重新啟動專案後,繼續使用之前報錯的查詢,GraphiQL就會給出校驗錯誤。

變數

現在是時候將引數變成動態了。 我們不希望每次在查詢中寫死查詢條件,我們希望這個查詢引數是動態的,這時候我們就需要使用到變數。

首先,這裡我們需要確保我們的GraphQL中介軟體可以接受引數,所以我們需要在GraphQLRequest類中新增一個引數變數

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

然後我們需要修改GraphQLMiddleware中介軟體的InvokeAsync方法, 在其中新增一行程式碼設定doc.Inputs

var result = await _executor.ExecuteAsync(doc =>
{
    doc.Schema = _schema;
    doc.Query = request.Query;

    doc.Inputs = request.Variables.ToInputs();

}).ConfigureAwait(false);

現在我們的item查詢已經支援動態引數了,我們可以執行程式,在GraphiQL中設定如下查詢

query($barcode: String!){  
  item(barcode: $barcode){
    title
    sellingPrice
  }
}

查詢中變數是以$開頭的, 後面需要加上變數型別,因為之前我們這是了barcode引數為必填項,所以$barcode變數我們也要設定成必填。變數的必填設定是在變數型別後新增一個!號。

最後,在GraphiQL中,你可以使用QUERY VARIABLES面板中輸入引數的值。如下圖所示,最終結果正確的返回了。

本文原始碼:https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20V