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