• 造轮子之集成GraphQL


    先简单对比以下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中添加代码

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

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

    实现QueryType#

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

    using HotChocolate.Authorization;
    
    namespace Wheel.Graphql
    {
        [Authorize]
        public class Query : IQuery
        {
        }
    
        [InterfaceType]
        public interface IQuery
        {
    
        }
    }
    
    

    在AddGraphQLServer()后面添加代码

    builder.Services.AddGraphQLServer()
                .AddQueryType()
        ;
    

    使用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()
                ;
    
                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自动生成了我们的两个查询。
    image.png

    添加授权#

    安装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()
                ;
    
                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。
    image.png
    获取一个token之后配置一下:
    image.png
    再次请求,可以看到正常查询。
    image.png

    集成现有Service#

    改造一下SampleQuery

    [ExtendObjectType(typeof(IQuery))]
    public class SampleQuery : IQueryExtendObjectType
    {
        public async Task> Sample([Service] IPermissionManageAppService permissionManageAppService)
        {
            var result = await permissionManageAppService.GetPermission();
            return result.Data;
        }
    }
    

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

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

    public class SampleQuery : IQueryExtendObjectType
    {
        public async Task> Sample([Service] IPermissionManageAppService permissionManageAppService)
        {
            var result = await permissionManageAppService.GetPermission();
            return result.Data;
        }
        public async Task> SampleUser(UserPageRequest pageRequest, [Service] IUserManageAppService userManageAppService)
        {
            var result = await userManageAppService.GetUserPageList(pageRequest);
            return result;
        }
    }
    

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

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

    image.png

  • 相关阅读:
    E - Fire! (双向bfs)
    Zabbix“专家坐诊”第207期问答汇总
    【模拟string函数的实现】
    使用mumu模拟器抓包 andriod app
    锁竞争导致的慢sql分析
    SystemVerilog——class类
    Neo4j CQL
    Jetson NX安装opencv3.2.0报错及问题汇总
    ROS2的cv_bridge和opencv版本不匹配问题
    java计算机毕业设计酒店预约入住系统源码+mysql数据库+系统+lw文档+部署
  • 原文地址:https://www.cnblogs.com/fanshaoO/p/17767098.html