• 我封装的一个REPR轮子 Biwen.QuickApi


    Biwen.QuickApi

    项目介绍

    [QuickApi("hello/world")]
    public class MyApi : BaseQuickApi<Req,Rsp>{}
    
    • 提供一种简单集成的Minimal Web Api交互模块 遵循了 REPR 设计 (Request-Endpoint-Response)
    • 开箱即用的Api路由 和 权限,Bind,validator体验
    • 该库是NET WebApi/Minimal Api的补充,性能≈MinimalApi,遥遥领先于MVC和WebApi,但是提供了最简单的的使用体验
    • write less, do more ; write anywhere, do anything
    • 欢迎小伙伴们star&issue共同学习进步 (Biwen.QuickApi)[https://github.com/vipwan/Biwen.QuickApi]

    使用方式

    Step0 Nuget Install

    dotnet add package Biwen.QuickApi
    

    Step1 UseBiwenQuickApis

    
    builder.Services.AddBiwenQuickApis(o =>
    {
        o.RoutePrefix = "quick";
        //不需要驼峰模式设置为null
        //o.JsonSerializerOptions.PropertyNamingPolicy = null;
    });
    
    //....
    app.MapBiwenQuickApis();
    
    

    Step2 Define Request and Response

    
        public class HelloApiRequest : BaseRequest<HelloApiRequest>
        {
            public string? Name { get; set; }
    
            /// 
            /// 别名绑定字段
            /// 
            [AliasAs("a")]
            public string? Alias { get; set; }
    
            public HelloApiRequest()
            {
                RuleFor(x => x.Name).NotNull().Length(5, 10);
            }
        }
    
        /// 
        /// 模拟自定义绑定的Request
        /// 
        public class CustomApiRequest : BaseRequest<CustomApiRequest>
        {
            public string? Name { get; set; }
    
            public CustomApiRequest()
            {
                RuleFor(x => x.Name).NotNull().Length(5, 10);
            }
        }
    
        /// 
        /// 自定义的绑定器
        /// 
        public class CustomApiRequestBinder : IReqBinder<CustomApiRequest>
        {
            public async Task BindAsync(HttpContext context)
            {
                var request = new CustomApiRequest
                {
                    Name = context.Request.Query["c"]
                };
                await Task.CompletedTask;
                return request;
            }
        }
    
        public class HelloApiResponse : BaseResponse
        {
            public string? Message { get; set; }
        }
    
    

    Step3 Define QuickApi

    
        /// 
        /// get ~/admin/index
        /// 
        [QuickApi("index", Group = "admin", Verbs = Verb.GET | Verb.POST, Policy = "admin")]
        public class NeedAuthApi : BaseQuickApi
        {
            public override EmptyResponse Execute(EmptyRequest request)
            {
                return EmptyResponse.Instance;
            }
        }
    
        /// 
        /// get ~/hello/world/{name}
        /// 
        [QuickApi("world/{name}", Group = "hello", Verbs = Verb.GET | Verb.POST)]
        public class HelloApi : BaseQuickApi<HelloApiRequest, HelloApiResponse>
        {
            private readonly HelloService _service;
            private readonly IHttpContextAccessor _httpContextAccessor;
    
            public Hello4Api(HelloService service,IHttpContextAccessor httpContextAccessor)
            {
                _service = service;
                _httpContextAccessor = httpContextAccessor;
            }
    
            public override HelloApiResponse Execute(HelloApiRequest request)
            {
                var hello = _service.Hello($"hello world {_httpContextAccessor.HttpContext!.Request.Path} !");
                return new HelloApiResponse
                {
                    Message = hello
                };
            }
        }
    
        /// 
        /// get ~/custom?c=11112222
        /// 
        [QuickApi("custom", Verbs = Verb.GET)]
        public class CustomApi : BaseQuickApi<CustomApiRequest>
        {
            public CustomApi()
            {
                UseReqBinder();
            }
    
            public override async Task ExecuteAsync(CustomApiRequest request)
            {
                await Task.CompletedTask;
                Console.WriteLine($"获取自定义的 CustomApi:,从querystring:c绑定,{request.Name}");
                return EmptyResponse.New;
            }
    
            /// 
            /// 提供minimal扩展
            /// 
            /// 
            /// 
            public override RouteHandlerBuilder HandlerBuilder(RouteHandlerBuilder builder)
            {
                //自定义描述
                builder.WithOpenApi(operation => new(operation)
                {
                    Summary = "This is a summary",
                    Description = "This is a description"
                });
    
                //自定义标签
                builder.WithTags("custom");
    
                //自定义过滤器
                builder.AddEndpointFilter(async (context, next) =>
                {
                    Console.WriteLine("自定义过滤器!");
                    return await next(context);
                });
    
                //自定义Api版本
                //默认为版本1.0,如果需要访问其他版本,需要在querystring中添加?api-version=2.0 :)
                builder.HasApiVersion(1.0).WithGroupName("1.0");
                builder.HasApiVersion(2.0).WithGroupName("2.0");
    
                return builder;
            }
    
        }
    
    
    

    Step4 Enjoy !

    
    //直接访问
    // GET ~/hello/world/biwen
    // GET ~/hello/world/biwen?name=biwen
    // POST ~/hello/world/biwen
    // GET ~/custom?c=11112222
    
    
    
    //你也可以把QuickApi当Service使用
    app.MapGet("/fromapi", async (Biwen.QuickApi.DemoWeb.Apis.Hello4Api api) =>
    {
        //通过你的方式获取请求对象
        var req = new EmptyRequest();
        //验证请求对象
        var result = req.RealValidator.Validate(req);
        if (!result.IsValid)
        {
            return Results.BadRequest(result.ToDictionary());
        }
        //执行请求
        var x = await api.ExecuteAsync(new EmptyRequest());
        return Results.Ok(x);
    });
    
    

    Step5 OpenApi 以及Client代理

    • 你可以全局配置版本号,以及自定义的OpenApi描述
    • 你可以重写QuickApi的HandlerBuilder方法,以便于你自定义的OpenApi描述
    • 我们强烈建议您使用Refit风格直接撸接口,以便于您的客户端和服务端保持一致的接口定义
    • 因为遵循REPR风格,所以不推荐SwaggerUI或使用SwaggerStudio生成代理代码,除非您的QuickApi定义的相当规范(如存在自定义绑定,别名绑定等)!
    
    /// 
    /// refit client
    /// 
    public interface IBusiness
    {
        [Refit.Get("/fromapi")]
        public Task<TestRsp> TestPost();
    }
    
    //Refit
    builder.Services.AddRefitClient()
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5101"));
    
    var app = builder.Build();
    
    app.MapGet("/from-quickapi", async (IBusiness bussiness) =>
    {
        var resp = await bussiness.TestPost();
        return Results.Content(resp.Message);
    });
    
    

    Q&A

    • 为什么不支持多个参数的绑定?
      -- 因为我认为这样的Api设计是不合理的,我们遵循REPR设计理念,如果你需要多个参数,请使用复杂化的Request对象

    • QuickApi中如何拿到HttpContext对象?
      -- 请在构造函数中注入IHttpContextAccessor获取

    • 是否支持Minimal的中间件和拦截器?
      -- 支持的,本身QuickApi就是扩展了MinimalApi,底层也是Minimal的处理机制,所以请考虑全局的中间件和拦截器,以及重写QuickApi的HandlerBuilder方法

  • 相关阅读:
    Python常用基础语法知识点大全
    一文详解:什么是进销存管理系统?2023年top10进销存管理系统大推荐!
    【Verilog基础】【计算机体系架构】一文搞懂 Cache 缓存(cache line、标记Tag、组号/行号index,块内地址offset)
    【LLM】金融大模型场景和大模型Lora微调实战
    python自动化测试工具selenium
    MySQL MVVC多版本并发控制
    建陶行业标杆『诺贝尔瓷砖』&企企通供应链协同系统一期项目上线,数字采购领航企业高质量发展
    Tronapi-波场接口-源码无加密-可二开--附接口文档-基于ThinkPHP5封装-作者详细指导-2022年7月1日08:43:06
    课堂练习P181最后一问:应回
    基于Qt QSlider滑动条小项目
  • 原文地址:https://www.cnblogs.com/vipwan/p/biwen-quickapi.html