经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
造轮子之集成GraphQL
来源:cnblogs  作者:饭勺oO  时间:2023/10/17 11:03:34  对本文有异议

先简单对比以下GraphQL和WebAPI:
GraphQL和Web API(如RESTful API)是用于构建和提供Web服务的不同技术。

  1. 数据获取方式:
  • Web API:通常使用RESTful API,客户端通过发送HTTP请求(如GET、POST、PUT、DELETE)来获取特定的数据。每个请求通常返回一个固定的数据结构,包含在响应的主体中。
  • GraphQL:客户端可以使用GraphQL查询语言来精确指定需要的数据。客户端发送一个GraphQL查询请求,服务器根据查询的结构和字段来返回相应的数据。
  1. 数据获取效率:
  • Web API:每个请求返回的数据通常是预定义的,无论客户端需要的数据量大小,服务器都会返回相同的数据结构。这可能导致客户端获取到不必要的数据,或者需要发起多个请求来获取所需数据。
  • GraphQL:客户端可以精确指定需要的数据,避免了不必要的数据传输。客户端可以在一个请求中获取多个资源,并且可以根据需要进行字段选择、过滤、排序等操作,从而提高数据获取效率。
  1. 版本管理:
  • Web API:通常使用URL版本控制或者自定义的HTTP头来管理API的版本。当API发生变化时,可能需要创建新的URL或者HTTP头来支持新的版本。
  • GraphQL:GraphQL中没有显式的版本控制机制,而是通过向现有的类型和字段添加新的字段来扩展现有的API。这样可以避免创建多个不同版本的API。
  1. 客户端开发体验:
  • Web API:客户端需要根据API的文档来构造请求和解析响应。客户端需要手动处理不同的API端点和数据结构。
  • GraphQL:客户端可以使用GraphQL的强类型系统和自动生成的代码工具来进行开发。客户端可以根据GraphQL的模式自动生成类型定义和查询代码,提供了更好的开发体验和类型安全性。

在前面我们基础框架是基于WebAPI(REST FUL API)的模式去开发接口的,所有的响应数据都需要定义一个DTO结构,但是有些场景可能只需要某些字段,而后端又懒得定义新数据接口对接,这就会导致客户端获取到不必要的数据。在这种情况下,使用GraphQL就可以有较好的体验。

那么,在我们现有写好的Service中,如何快速集成GraphQL又无需复杂编码工作呢。这就是我们接下来要实现的了。

HotChocolate.AspNetCore

HotChocolate.AspNetCore是.NET一个老牌的GraphQL实现库,它可以让我们很快速的实现一个GraphQL Server。
安装HotChocolate.AspNetCore的nuget,在Program中添加代码

  1. builder.Services.AddGraphQLServer()
  2. app.MapGraphQL();

这样就完成一个GraphQLServer的集成。
启动程序,访问https://localhost:7080/graphql/ 可以看到集成的界面。可以使用这个界面操作测试我们的graphql查询。
image.png

实现QueryType

接下来实现一个基础的QueryType,用于扩展查询。

  1. using HotChocolate.Authorization;
  2. namespace Wheel.Graphql
  3. {
  4. [Authorize]
  5. public class Query : IQuery
  6. {
  7. }
  8. [InterfaceType]
  9. public interface IQuery
  10. {
  11. }
  12. }

在AddGraphQLServer()后面添加代码

  1. builder.Services.AddGraphQLServer()
  2. .AddQueryType<Query>()
  3. ;

使用ExtendObjectType扩展Query类,方便接口拆分。

  1. public interface IQueryExtendObjectType
  2. {
  3. }
  4. [ExtendObjectType(typeof(IQuery))]
  5. public class SampleQuery : IQueryExtendObjectType
  6. {
  7. public List<string> Sample()
  8. {
  9. return new List<string> { "sample1", "sample2" };
  10. }
  11. }
  12. [ExtendObjectType(typeof(IQuery))]
  13. public class Sample2Query : IQueryExtendObjectType
  14. {
  15. public string Sample2(string id)
  16. {
  17. return id;
  18. }
  19. }

这里创建一个IQueryExtendObjectType空接口,用于获取所有需要扩展的QueryAPI
约定所有扩展的Query需要继承IQueryExtendObjectType接口,并加上ExtendObjectType特性标签。
封装AddGraphQLServer方法:

  1. using HotChocolate.Execution.Configuration;
  2. using System.Reflection;
  3. namespace Wheel.Graphql
  4. {
  5. public static class GraphQLExtensions
  6. {
  7. public static IRequestExecutorBuilder AddWheelGraphQL(this IServiceCollection services)
  8. {
  9. var result = services.AddGraphQLServer()
  10. .AddQueryType<Query>()
  11. ;
  12. var abs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
  13. .Where(x => !x.Contains("Microsoft.") && !x.Contains("System."))
  14. .Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))).ToArray();
  15. var types = abs.SelectMany(ab => ab.GetTypes()
  16. .Where(t => typeof(IQueryExtendObjectType).IsAssignableFrom(t) && typeof(IQueryExtendObjectType) != t));
  17. if (types.Any())
  18. {
  19. result = result.AddTypes(types.ToArray());
  20. }
  21. return result;
  22. }
  23. }
  24. }

遍历所有IQueryExtendObjectType并加入GraphQLServer。
启动项目访问https://localhost:7080/graphql/
可以看到SchemaDefinition自动生成了我们的两个查询。
image.png

添加授权

安装HotChocolate.AspNetCore.Authorization的Nuget包。
在services.AddGraphQLServer()后面添加代码.AddAuthorization()

  1. using HotChocolate.Execution.Configuration;
  2. using System.Reflection;
  3. namespace Wheel.Graphql
  4. {
  5. public static class GraphQLExtensions
  6. {
  7. public static IRequestExecutorBuilder AddWheelGraphQL(this IServiceCollection services)
  8. {
  9. var result = services.AddGraphQLServer()
  10. .AddAuthorization()
  11. .AddQueryType<Query>()
  12. ;
  13. var abs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
  14. .Where(x => !x.Contains("Microsoft.") && !x.Contains("System."))
  15. .Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))).ToArray();
  16. var types = abs.SelectMany(ab => ab.GetTypes()
  17. .Where(t => typeof(IQueryExtendObjectType).IsAssignableFrom(t) && typeof(IQueryExtendObjectType) != t));
  18. if (types.Any())
  19. {
  20. result = result.AddTypes(types.ToArray());
  21. }
  22. return result;
  23. }
  24. }
  25. }

未登录前执行查询,可以看到响应Error。
image.png
获取一个token之后配置一下:
image.png
再次请求,可以看到正常查询。
image.png

集成现有Service

改造一下SampleQuery

  1. [ExtendObjectType(typeof(IQuery))]
  2. public class SampleQuery : IQueryExtendObjectType
  3. {
  4. public async Task<List<GetAllPermissionDto>> Sample([Service] IPermissionManageAppService permissionManageAppService)
  5. {
  6. var result = await permissionManageAppService.GetPermission();
  7. return result.Data;
  8. }
  9. }

打开https://localhost:7080/graphql/ 执行查询,可以看到正常返回。
image.png
当我们需要过滤不查询某些字段时,只需要修改Query查询格式。
image.png

分页查询,添加一下User的分页查询代码。

  1. public class SampleQuery : IQueryExtendObjectType
  2. {
  3. public async Task<List<GetAllPermissionDto>> Sample([Service] IPermissionManageAppService permissionManageAppService)
  4. {
  5. var result = await permissionManageAppService.GetPermission();
  6. return result.Data;
  7. }
  8. public async Task<Page<UserDto>> SampleUser(UserPageRequest pageRequest, [Service] IUserManageAppService userManageAppService)
  9. {
  10. var result = await userManageAppService.GetUserPageList(pageRequest);
  11. return result;
  12. }
  13. }

测试:
image.png
可以看到,很简单就可以把现有的API转换成GraphQL。只不过一些排序分页逻辑我们没有采用GraphQL的方式,而是使用我们自己的WebApi分页查询的模式。

轮子仓库地址https://github.com/Wheel-Framework/Wheel
欢迎进群催更。

image.png

原文链接:https://www.cnblogs.com/fanshaoO/p/17767098.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号