在 RESTful API 中,通常有多个服务服务于不同的目的。虽然为每个独特的请求创建单独的服务很诱人,但它可能会导致不必要的重复和臃肿的架构。 ServiceStack 提倡一种不同的方法,鼓励根据调用语义和响应类型对服务进行分组。
服务操作(请求 DTO)应该捕获服务的独特操作服务,而它们返回的 DTO 类型代表实体或数据容器。请求 DTO 应使用动词(例如“获取”、“查找”)来表达其操作,而 DTO 类型应使用名词(例如“客户”、“产品”)来表示其实体。
在典型的 GET 请求的情况下,ServiceStack 不需要响应 DTO 中的 ResponseStatus 属性。相反,如果发生错误,将抛出通用 ErrorResponse DTO 并在客户端上序列化。这消除了在响应中使用显式 ResponseStatus 属性的需要。
为了增强可读性和自我描述,建议在服务合同中使用一致的命名法。为基于唯一标识符检索单个结果的服务保留“获取”动词。对于返回多个结果的搜索服务,请使用“查找”或“搜索”前缀。此外,提供清晰且描述性的属性名称,以表明其在请求 DTO 中的用途。
根据这些原则,建议使用以下重构的预订限制服务:
[Route("/bookinglimits/{Id}")] public class GetBookingLimit : IReturn<BookingLimit> { public int Id { get; set; } } public class BookingLimit { public int Id { get; set; } public int ShiftId { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public int Limit { get; set; } } [Route("/bookinglimits/search")] public class FindBookingLimits : IReturn<List<BookingLimit>> { public DateTime BookedAfter { get; set; } }
服务实现可以通过应用[Authenticate]来简化属性在服务类上一次,而不是每个请求 DTO。以下代码显示了此实现:
[Authenticate] public class BookingLimitService : AppServiceBase { public BookingLimit Get(GetBookingLimit request) { ... } public List<BookingLimit> Get(FindBookingLimits request) { ... } }
可以使用 ServiceStack 内置的 Fluent 验证功能来自定义错误处理和验证。您可以使用以下行在 AppHost 中注册验证器,而不是将验证器注入到服务中:
container.RegisterValidators(typeof(CreateBookingValidator).Assembly);
对于具有副作用的操作(例如,POST/PUT),您可以定义如下验证器:
public class CreateBookingValidator : AbstractValidator<CreateBooking> { public CreateBookingValidator() { RuleFor(r => r.StartDate).NotEmpty(); RuleFor(r => r.ShiftId).GreaterThan(0); RuleFor(r => r.Limit).GreaterThan(0); } }
以上是如何在ServiceStack中设计高效且一致的请求DTO?的详细内容。更多信息请关注PHP中文网其他相关文章!