先簡單對比以下GraphQL和WebAPI:
GraphQL和Web API(如RESTful API)是用於構建和提供Web服務的不同技術。
在前面我們基礎框架是基於WebAPI(REST FUL API)的模式去開發介面的,所有的響應資料都需要定義一個DTO結構,但是有些場景可能只需要某些欄位,而後端又懶得定義新資料介面對接,這就會導致使用者端獲取到不必要的資料。在這種情況下,使用GraphQL就可以有較好的體驗。
那麼,在我們現有寫好的Service中,如何快速整合GraphQL又無需複雜編碼工作呢。這就是我們接下來要實現的了。
HotChocolate.AspNetCore是.NET一個老牌的GraphQL實現庫,它可以讓我們很快速的實現一個GraphQL Server。
安裝HotChocolate.AspNetCore的nuget,在Program中新增程式碼
builder.Services.AddGraphQLServer()
app.MapGraphQL();
這樣就完成一個GraphQLServer的整合。
啟動程式,存取https://localhost:7080/graphql/ 可以看到整合的介面。可以使用這個介面操作測試我們的graphql查詢。
接下來實現一個基礎的QueryType,用於擴充套件查詢。
using HotChocolate.Authorization;
namespace Wheel.Graphql
{
[Authorize]
public class Query : IQuery
{
}
[InterfaceType]
public interface IQuery
{
}
}
在AddGraphQLServer()後面新增程式碼
builder.Services.AddGraphQLServer()
.AddQueryType<Query>()
;
使用ExtendObjectType擴充套件Query類,方便介面拆分。
public interface IQueryExtendObjectType
{
}
[ExtendObjectType(typeof(IQuery))]
public class SampleQuery : IQueryExtendObjectType
{
public List<string> Sample()
{
return new List<string> { "sample1", "sample2" };
}
}
[ExtendObjectType(typeof(IQuery))]
public class Sample2Query : IQueryExtendObjectType
{
public string Sample2(string id)
{
return id;
}
}
這裡建立一個IQueryExtendObjectType空介面,用於獲取所有需要擴充套件的QueryAPI
約定所有擴充套件的Query需要繼承IQueryExtendObjectType介面,並加上ExtendObjectType特性標籤。
封裝AddGraphQLServer方法:
using HotChocolate.Execution.Configuration;
using System.Reflection;
namespace Wheel.Graphql
{
public static class GraphQLExtensions
{
public static IRequestExecutorBuilder AddWheelGraphQL(this IServiceCollection services)
{
var result = services.AddGraphQLServer()
.AddQueryType<Query>()
;
var abs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
.Where(x => !x.Contains("Microsoft.") && !x.Contains("System."))
.Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))).ToArray();
var types = abs.SelectMany(ab => ab.GetTypes()
.Where(t => typeof(IQueryExtendObjectType).IsAssignableFrom(t) && typeof(IQueryExtendObjectType) != t));
if (types.Any())
{
result = result.AddTypes(types.ToArray());
}
return result;
}
}
}
遍歷所有IQueryExtendObjectType並加入GraphQLServer。
啟動專案存取https://localhost:7080/graphql/
可以看到SchemaDefinition自動生成了我們的兩個查詢。
安裝HotChocolate.AspNetCore.Authorization的Nuget包。
在services.AddGraphQLServer()後面新增程式碼.AddAuthorization()
using HotChocolate.Execution.Configuration;
using System.Reflection;
namespace Wheel.Graphql
{
public static class GraphQLExtensions
{
public static IRequestExecutorBuilder AddWheelGraphQL(this IServiceCollection services)
{
var result = services.AddGraphQLServer()
.AddAuthorization()
.AddQueryType<Query>()
;
var abs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
.Where(x => !x.Contains("Microsoft.") && !x.Contains("System."))
.Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))).ToArray();
var types = abs.SelectMany(ab => ab.GetTypes()
.Where(t => typeof(IQueryExtendObjectType).IsAssignableFrom(t) && typeof(IQueryExtendObjectType) != t));
if (types.Any())
{
result = result.AddTypes(types.ToArray());
}
return result;
}
}
}
未登入前執行查詢,可以看到響應Error。
獲取一個token之後設定一下:
再次請求,可以看到正常查詢。
改造一下SampleQuery
[ExtendObjectType(typeof(IQuery))]
public class SampleQuery : IQueryExtendObjectType
{
public async Task<List<GetAllPermissionDto>> Sample([Service] IPermissionManageAppService permissionManageAppService)
{
var result = await permissionManageAppService.GetPermission();
return result.Data;
}
}
開啟https://localhost:7080/graphql/ 執行查詢,可以看到正常返回。
當我們需要過濾不查詢某些欄位時,只需要修改Query查詢格式。
分頁查詢,新增一下User的分頁查詢程式碼。
public class SampleQuery : IQueryExtendObjectType
{
public async Task<List<GetAllPermissionDto>> Sample([Service] IPermissionManageAppService permissionManageAppService)
{
var result = await permissionManageAppService.GetPermission();
return result.Data;
}
public async Task<Page<UserDto>> SampleUser(UserPageRequest pageRequest, [Service] IUserManageAppService userManageAppService)
{
var result = await userManageAppService.GetUserPageList(pageRequest);
return result;
}
}
測試:
可以看到,很簡單就可以把現有的API轉換成GraphQL。只不過一些排序分頁邏輯我們沒有采用GraphQL的方式,而是使用我們自己的WebApi分頁查詢的模式。
輪子倉庫地址https://github.com/Wheel-Framework/Wheel
歡迎進群催更。