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方法

我封装的一个REPR轮子 Biwen.QuickApi的更多相关文章

  1. 自己封装的一个LoadRes组件

    这两周一直太忙,没有好好处理上上上周遇到的一个让我加班到凌晨的问题,这个问题是判断flash的加载. 之前的思路是让flash的人在制作flash的时候,加入了一个回调方法,该方法再会回调我页面的方法 ...

  2. 自己封装的一个JS分享组件

    因为工作的需求之前也封装过一个JS分享插件,集成了我们公司常用的几个分享平台. 但是总感觉之前的结构上很不理想,样式,行为揉成一起,心里想的做的完美,实际上总是很多的偏差,所以这次我对其进行了改版. ...

  3. 使用原生JS实现一个风箱式的demo,并封装了一个运动框架

    声明,该DEMO依托于某个培训机构中,非常感谢这个培训结构.话不多说,现在开始改demo的制作. 首先,在前端的学习过程中,轮播图是我们一定要学习的,所以为了更加高效的实现各种轮播图,封装了一个运动的 ...

  4. 使用 ViewPager 和 RadioGroup 封装的一个导航控件

    import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.dra ...

  5. 在jsp提交表单的参数封装到一个方法里

    建议去看一下孤傲苍狼写的Servlet+JSP+JavaBean开发模式(http://www.cnblogs.com/xdp-gacl/p/3902537.html), 最好把他JavaWeb学习总 ...

  6. 自己封装的一个js方法用于获取显示的星期和日期时间

    自己封装的一个js方法用于获取显示的星期和日期时间 /** * 获取用于显示的星期和日期时间 * @param date * @returns {string} */ function getWeek ...

  7. 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil

    基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...

  8. Timber(对Log类封装的一个工具)

    Timber(对Log类封装的一个工具) https://blog.csdn.net/hzl9966/article/details/51314137 https://www.jianshu.com/ ...

  9. SpringMVC 中,当前台传入多个参数时,可将参数封装成一个bean类

    在实际业务场景中,当前台通过 url 向后台传送多个参数时,可以将参数封装成一个bean类,在bean类中对各个参数进行非空,默认值等的设置. 前台 url ,想后台传送两个参数,userName 和 ...

  10. 封装的一个sorted_vector示例,实现了stl::set的一部分接口

           STL set能保证最坏情况下的查找和插入效率,logN.但是维护红黑树开销较大.set内的元素按照一定的逻辑顺序组织,查找.插入等操作的结果都和排序规则有关.       适合STL ...

随机推荐

  1. WPF 入门笔记 - 03 - 样式基础及模板

    程序的本质 - 数据结构 + 算法 本篇为学习李应保老师所著的<WPF专业编程指南>并搭配WPF开发圣经<WPF编程宝典第4版>以及痕迹大佬<WPF入门基础教程系列> ...

  2. ChatGPT+Mermaid自然语言流程图形化产出小试

    ChatGPT+Mermaid语言实现技术概念可视化 本文旨在介绍如何使用ChatGPT和Mermaid语言生成流程图的技术.在现代软件开发中,流程图是一种重要的工具,用于可视化和呈现各种流程和结构. ...

  3. FPGA加速技术在游戏和娱乐系统中的应用:实现高效的游戏和娱乐系统

    目录 1. 引言 2. 技术原理及概念 3. 实现步骤与流程 4. 应用示例与代码实现讲解 <35. FPGA加速技术在游戏和娱乐系统中的应用:实现高效的游戏和娱乐系统>这篇文章是一篇针对 ...

  4. Nmap使用教程(初级篇)

    基本扫描技术 扫描单个网络 nmap 192.168.1.1/www.baidu.com 扫描多个网络/目标 nmap 192.168.1.1 192.168.1.2 #将扫描同个网段内不同的ip地址 ...

  5. 【.Net/C#之ChatGPT开发系列】四、ChatGPT多KEY动态轮询,自动删除无效KEY

    ChatGPT是一种基于Token数量计费的语言模型,它可以生成高质量的文本.然而,每个新账号只有一个有限的初始配额,用完后就需要付费才能继续使用.为此,我们可能存在使用多KEY的情况,并在每个KEY ...

  6. ASL单芯片CS5366TypeC转HDMI4K60HZ加HUB多口方案|CS5366带PD拓展方案原理图

    CS5366芯片是ASL集睿致远最新推出的2Len带PD的扩展坞方案芯片,CS5366支持4K60HZ. 在分辨率4K下,刷新率60HZ对于30HZ看似提升不多,但是对于应用在游戏主座的客户来说至关重 ...

  7. 用写代码的方式画图-试下PlantUML吧

    1 序言 所谓一图胜千言,大家平日在工作中编写文档时,往往都需要画各种图来表达中心思想,比如流程图.时序图.UML 图,很多人选择使用 Axure .PrecessOn.Diagrams(darw.i ...

  8. 基于ClickHouse解决活动海量数据问题

    1.背景 魔笛活动平台要记录每个活动的用户行为数据,帮助客服.运营.产品.研发等快速处理客诉.解决线上问题并进行相关数据分析和报警.可以预见到需要存储和分析海量数据,预估至少几十亿甚至上百亿的数据量, ...

  9. C标准库 操作文件

    C标准库 操作文件 数据持久化的两种方法:文件和数据库 文本文件和二进制文件 举个例子,写C++的代码,源代码为文本文件.编译出来的可执行文件(.exe)文件是二进制文件 文本文件 以文本的编码(AS ...

  10. 侯捷C++STL源码分析

    STL六大部件 容器(Containers):放东西,需要占用内存. 分配器(Allocators):支持容器. 算法(Algorithms):操作容器里面的数据. 迭代器(Iterators):容器 ...