找回密码
 立即注册
首页 业界区 业界 优雅的.net REST API之FastEndpoints

优雅的.net REST API之FastEndpoints

鞠彗云 昨天 10:12
FastEndpoints 是基于 ASP.NET Core 的轻量级、高性能 Web API 开发框架,采用 REPR (请求-端点-响应)设计模式。
 
本人用FastEndpoints做了一个REST API很优雅的Case
 
一、以下是http测试
  1. @HostAddress = http://localhost:5167
  2. ### 获取列表
  3. GET {{HostAddress}}/users?Page=1&Size=10
  4. ### 添加
  5. PUT {{HostAddress}}/users
  6. Content-Type:application/json
  7. {
  8.   "Name" : "Jxj"
  9. }
  10. ### 获取单个
  11. GET {{HostAddress}}/users/1
  12. ### 修改
  13. PATCH {{HostAddress}}/users/1
  14. Content-Type:application/json
  15. {
  16.   "Name" : "Jxj2"
  17. }
  18. ### 删除
  19. DELETE {{HostAddress}}/users/1
复制代码
地址规则非常简单清晰,只有两种地址却能支持添、删、改、查四种操作
1. 添加使用/users
  使用PUT请求,含义是向一个集合添加资源
2. 删除使用/users/{Id}(Id是标识)
  使用DELETE请求,表示从集合移除该标识的资源
3. 修改也使用/users/{Id}}(Id是标识)
  使用PATCH请求,表示该标识资源的哪些字段被修改了(这与Elasticsearch的一样)
4. 查询GET请求
4.1 查询单条使用/users/{Id}}(Id是标识)
4.2 查询多条使用/users
 
二、项目结构也是非常简单清晰
1.png

 注:实际项目的模型和仓储应该是单独项目,这里简单示意就放一起了
本人非常喜欢这样的项目结构,每个API方法一个文件夹
而且每个文件夹下的文件名非常有意思,都是Endpoint、Mapper和Models,对于本人这种纠结命名规则的反而是一种解脱
DTO直接命名为Request和Responce,如果是复杂结构可以增加DTO类型
应用层业务逻辑复杂的可以再增加一个Data.cs文件
这种文件结构FastEndpoints是有提供模板生成的,当然手动写也不复杂
 
三、Mapper的优雅实现
定义接口IPocoConverter实现任意两种类型的转化,直接用IOC注入就好了
以下是Create的Mapper的实现
  1. [RegisterService<Mapper>(LifeTime.Singleton)]
  2. public sealed class Mapper(
  3.     UserRepository repository,
  4.     IPocoConverter<Request, User> requestConverter,
  5.     IPocoConverter<User, Response> responseConverter)
  6.     : Mapper<Request, Response, User>
  7. {
  8.     #region 配置
  9.     private readonly UserRepository _repository = repository;
  10.     private readonly IPocoConverter<Request, User> _requestConverter = requestConverter;
  11.     private readonly IPocoConverter<User, Response> _responseConverter = responseConverter;
  12.     #endregion
  13.     public override User ToEntity(Request r)
  14.     {
  15.         User entity = _requestConverter.Convert(r);
  16.         return Save(entity);
  17.     }
  18.     public override Response FromEntity(User e)
  19.         => _responseConverter.Convert(e);
  20.     #region Data
  21.     User Save(User entity)
  22.         => _repository.Add(entity);
  23.     #endregion
  24. }
复制代码
这里有一个微软IOC不得不说的槽点,IServiceCollection支持泛型类的注册,却不支持泛型方法的注册
好在本人找到了博客园一个大佬(@coredx)的开源项目(https://www.cnblogs.com/coredx/p/18138360)
封装一个简单IOC注入泛型转化的方法如下:
  1. services.UseConverter(PocoEmit.Mapper.Global);
复制代码
还需要显示调用@coredx的以下方法
  1. builder.Host.UseServiceProviderFactory(new TypedImplementationFactoryServiceProviderFactory());
复制代码
注: 以上调用本人是翻开大佬源码才摸索出来的,按大佬的文档尝试了很多次都失败了,大佬的文档估计有些时间没更新了...
 
四、优雅的修改
本次修改还是使用的本人上篇文章(https://www.cnblogs.com/xiangji/p/18979384)提到的MyDelta,微软OData的Delta的变体
使用MyDelta,无论模型实体多少字段,都可以使用一个API方法实现
  1. public sealed class Endpoint(UserModifyDTOValidator validationRules) : Endpoint<Request, Response, Mapper>
  2. {
  3.     // ...
  4.     public override async Task HandleAsync(Request req, CancellationToken c)
  5.     {
  6.         MyDelta<UserModifyDTO> dto = req.User;
  7.         dto.Patch(dto.Instance);
  8.         var result = validationRules.Validate(dto);
  9.         if(!result.IsValid)
  10.         {
  11.             ThrowError(result.Errors[0]);
  12.         }
  13.         User? entity = Map.ToEntity(req);
  14.         if (entity is null)
  15.         {
  16.             ThrowError($"Id = {req.Id} 的User不存在");
  17.         }
  18.         var res = Map.FromEntity(entity);
  19.         await Send.OkAsync(res, c);
  20.     }
  21. }
复制代码
  1. [RegisterService<Mapper>(LifeTime.Singleton)]
  2. public sealed class Mapper(
  3.     UserRepository repository,
  4.     IMyDeltaFactory deltaFactory,
  5.     IPocoConverter<User, Response> responseConverter)
  6.     : Mapper<Request, Response, User?>
  7. {
  8.     // ...
  9.     public override User? ToEntity(Request r)
  10.     {
  11.         var user0 = GetById(r.Id);
  12.         if (user0 == null)
  13.             return null;
  14.         var delta = deltaFactory.Create(user0, r.User.Data);
  15.         return Modify(delta);
  16.     }
  17. }
复制代码
获取并验证DTO的MyDelta(增量),再转化为模型实体的增量,调用仓储处理
以下项目代码GitHub地址: https://github.com/donetsoftwork/MyEmit/tree/main/IntegrationTests/TestApi
gitee同步更新: https://gitee.com/donetsoftwork/MyEmit/tree/main/IntegrationTests/TestApi
 
如果大家喜欢请动动您发财的小手手帮忙点一下Star。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册