翼度科技»论坛 编程开发 .net 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
Biwen.QuickApi

项目介绍
  1. [QuickApi("hello/world")]
  2. 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
  1. dotnet add package Biwen.QuickApi
复制代码
Step1 UseBiwenQuickApis
  1. builder.Services.AddBiwenQuickApis(o =>
  2. {
  3.     o.RoutePrefix = "quick";
  4.     //不需要驼峰模式设置为null
  5.     //o.JsonSerializerOptions.PropertyNamingPolicy = null;
  6. });
  7. //....
  8. app.MapBiwenQuickApis();
复制代码
Step2 Define Request and Response
  1.     public class HelloApiRequest : BaseRequest<HelloApiRequest>
  2.     {
  3.         public string? Name { get; set; }
  4.         /// <summary>
  5.         /// 别名绑定字段
  6.         /// </summary>
  7.         [AliasAs("a")]
  8.         public string? Alias { get; set; }
  9.         public HelloApiRequest()
  10.         {
  11.             RuleFor(x => x.Name).NotNull().Length(5, 10);
  12.         }
  13.     }
  14.     /// <summary>
  15.     /// 模拟自定义绑定的Request
  16.     /// </summary>
  17.     public class CustomApiRequest : BaseRequest<CustomApiRequest>
  18.     {
  19.         public string? Name { get; set; }
  20.         public CustomApiRequest()
  21.         {
  22.             RuleFor(x => x.Name).NotNull().Length(5, 10);
  23.         }
  24.     }
  25.     /// <summary>
  26.     /// 自定义的绑定器
  27.     /// </summary>
  28.     public class CustomApiRequestBinder : IReqBinder<CustomApiRequest>
  29.     {
  30.         public async Task<CustomApiRequest> BindAsync(HttpContext context)
  31.         {
  32.             var request = new CustomApiRequest
  33.             {
  34.                 Name = context.Request.Query["c"]
  35.             };
  36.             await Task.CompletedTask;
  37.             return request;
  38.         }
  39.     }
  40.     public class HelloApiResponse : BaseResponse
  41.     {
  42.         public string? Message { get; set; }
  43.     }
复制代码
Step3 Define QuickApi
  1.     /// <summary>
  2.     /// get ~/admin/index
  3.     /// </summary>
  4.     [QuickApi("index", Group = "admin", Verbs = Verb.GET | Verb.POST, Policy = "admin")]
  5.     public class NeedAuthApi : BaseQuickApi
  6.     {
  7.         public override EmptyResponse Execute(EmptyRequest request)
  8.         {
  9.             return EmptyResponse.Instance;
  10.         }
  11.     }
  12.     /// <summary>
  13.     /// get ~/hello/world/{name}
  14.     /// </summary>
  15.     [QuickApi("world/{name}", Group = "hello", Verbs = Verb.GET | Verb.POST)]
  16.     public class HelloApi : BaseQuickApi<HelloApiRequest, HelloApiResponse>
  17.     {
  18.         private readonly HelloService _service;
  19.         private readonly IHttpContextAccessor _httpContextAccessor;
  20.         public Hello4Api(HelloService service,IHttpContextAccessor httpContextAccessor)
  21.         {
  22.             _service = service;
  23.             _httpContextAccessor = httpContextAccessor;
  24.         }
  25.         public override HelloApiResponse Execute(HelloApiRequest request)
  26.         {
  27.             var hello = _service.Hello($"hello world {_httpContextAccessor.HttpContext!.Request.Path} !");
  28.             return new HelloApiResponse
  29.             {
  30.                 Message = hello
  31.             };
  32.         }
  33.     }
  34.     /// <summary>
  35.     /// get ~/custom?c=11112222
  36.     /// </summary>
  37.     [QuickApi("custom", Verbs = Verb.GET)]
  38.     public class CustomApi : BaseQuickApi<CustomApiRequest>
  39.     {
  40.         public CustomApi()
  41.         {
  42.             UseReqBinder<CustomApiRequestBinder>();
  43.         }
  44.         public override async Task<EmptyResponse> ExecuteAsync(CustomApiRequest request)
  45.         {
  46.             await Task.CompletedTask;
  47.             Console.WriteLine($"获取自定义的 CustomApi:,从querystring:c绑定,{request.Name}");
  48.             return EmptyResponse.New;
  49.         }
  50.         /// <summary>
  51.         /// 提供minimal扩展
  52.         /// </summary>
  53.         /// <param name="builder"></param>
  54.         /// <returns></returns>
  55.         public override RouteHandlerBuilder HandlerBuilder(RouteHandlerBuilder builder)
  56.         {
  57.             //自定义描述
  58.             builder.WithOpenApi(operation => new(operation)
  59.             {
  60.                 Summary = "This is a summary",
  61.                 Description = "This is a description"
  62.             });
  63.             //自定义标签
  64.             builder.WithTags("custom");
  65.             //自定义过滤器
  66.             builder.AddEndpointFilter(async (context, next) =>
  67.             {
  68.                 Console.WriteLine("自定义过滤器!");
  69.                 return await next(context);
  70.             });
  71.             //自定义Api版本
  72.             //默认为版本1.0,如果需要访问其他版本,需要在querystring中添加?api-version=2.0 :)
  73.             builder.HasApiVersion(1.0).WithGroupName("1.0");
  74.             builder.HasApiVersion(2.0).WithGroupName("2.0");
  75.             return builder;
  76.         }
  77.     }
复制代码
Step4 Enjoy !
  1. //直接访问
  2. // GET ~/hello/world/biwen
  3. // GET ~/hello/world/biwen?name=biwen
  4. // POST ~/hello/world/biwen
  5. // GET ~/custom?c=11112222
复制代码
  1. //你也可以把QuickApi当Service使用
  2. app.MapGet("/fromapi", async (Biwen.QuickApi.DemoWeb.Apis.Hello4Api api) =>
  3. {
  4.     //通过你的方式获取请求对象
  5.     var req = new EmptyRequest();
  6.     //验证请求对象
  7.     var result = req.RealValidator.Validate(req);
  8.     if (!result.IsValid)
  9.     {
  10.         return Results.BadRequest(result.ToDictionary());
  11.     }
  12.     //执行请求
  13.     var x = await api.ExecuteAsync(new EmptyRequest());
  14.     return Results.Ok(x);
  15. });
复制代码
Step5 OpenApi 以及Client代理


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


  • 为什么不支持多个参数的绑定?
    -- 因为我认为这样的Api设计是不合理的,我们遵循REPR设计理念,如果你需要多个参数,请使用复杂化的Request对象
  • QuickApi中如何拿到HttpContext对象?
    -- 请在构造函数中注入IHttpContextAccessor获取
  • 是否支持Minimal的中间件和拦截器?
    -- 支持的,本身QuickApi就是扩展了MinimalApi,底层也是Minimal的处理机制,所以请考虑全局的中间件和拦截器,以及重写QuickApi的HandlerBuilder方法

来源:https://www.cnblogs.com/vipwan/archive/2023/09/24/biwen-quickapi.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具