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

  • 我封装的一个REPR轮子 Biwen.QuickApi已关闭评论
  • 190 次浏览
  • A+
所属分类:.NET技术
摘要

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


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; }          /// <summary>         /// 别名绑定字段         /// </summary>         [AliasAs("a")]         public string? Alias { get; set; }          public HelloApiRequest()         {             RuleFor(x => x.Name).NotNull().Length(5, 10);         }     }      /// <summary>     /// 模拟自定义绑定的Request     /// </summary>     public class CustomApiRequest : BaseRequest<CustomApiRequest>     {         public string? Name { get; set; }          public CustomApiRequest()         {             RuleFor(x => x.Name).NotNull().Length(5, 10);         }     }      /// <summary>     /// 自定义的绑定器     /// </summary>     public class CustomApiRequestBinder : IReqBinder<CustomApiRequest>     {         public async Task<CustomApiRequest> 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

     /// <summary>     /// get ~/admin/index     /// </summary>     [QuickApi("index", Group = "admin", Verbs = Verb.GET | Verb.POST, Policy = "admin")]     public class NeedAuthApi : BaseQuickApi     {         public override EmptyResponse Execute(EmptyRequest request)         {             return EmptyResponse.Instance;         }     }      /// <summary>     /// get ~/hello/world/{name}     /// </summary>     [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             };         }     }      /// <summary>     /// get ~/custom?c=11112222     /// </summary>     [QuickApi("custom", Verbs = Verb.GET)]     public class CustomApi : BaseQuickApi<CustomApiRequest>     {         public CustomApi()         {             UseReqBinder<CustomApiRequestBinder>();         }          public override async Task<EmptyResponse> ExecuteAsync(CustomApiRequest request)         {             await Task.CompletedTask;             Console.WriteLine($"获取自定义的 CustomApi:,从querystring:c绑定,{request.Name}");             return EmptyResponse.New;         }          /// <summary>         /// 提供minimal扩展         /// </summary>         /// <param name="builder"></param>         /// <returns></returns>         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定义的相当规范(如存在自定义绑定,别名绑定等)!
 /// <summary> /// refit client /// </summary> public interface IBusiness {     [Refit.Get("/fromapi")]     public Task<TestRsp> TestPost(); }  //Refit builder.Services.AddRefitClient<IBusiness>()     .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方法