ASP.NET Core中使用GraphQL - 第五章 欄位, 引數, 變數
ASP.NET Core中使用GraphQL
- ASP.NET Core中使用GraphQL - 第一章 Hello World
- ASP.NET Core中使用GraphQL - 第二章 中介軟體
- ASP.NET Core中使用GraphQL - 第三章 依賴注入
- ASP.NET Core中使用GraphQL - 第四章 GrahpiQL
欄位
我們已經很好的理解了GraphQL中的欄位。在之前HelloWorldQuery
的例子中,我們添加了2個欄位hello
和howdy
. 它們都是標量欄位。正如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