更多 ServiceStack 请求 DTO 建议 [英] More ServiceStack request DTO advice

查看:42
本文介绍了更多 ServiceStack 请求 DTO 建议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是关于以下方面的跟进:

This is a follow up regarding:

ServiceStack 请求 DTO 设计

在上述问题中,设计严格地针对读取操作.写操作呢?假设我们想添加用于创建新预订限制的操作,在这里重用名词是否合适?

In the above question the design was strictly regarding read operations. What about write operations? Say we wanted to add operations for creating a new booking limit, would reusing the noun be appropriate here?

[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{      
     BookingLimit newBookingLimit
}

-OR- 这会是更好的设计吗?

-OR- Would this be better design?

[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{      
  public int ShiftId { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
  public int Limit { get; set; }    }
}

另外,如果我们想添加编辑——我们是否应该插入和编辑共享相同的模型并添加 ID?

Also, if we wanted to add editing--should we have insert and edit share the same models and add the ID?

[Route("/bookinglimits/","POST")]
[Route("/bookinglimits/{Id}/","PUT")]
public class CreateBookingLimit : IReturn<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; }    }
}

我正在努力思考什么时候重用 POCO 最有意义,什么时候分离意图更有意义.

I'm trying to wrap my head around when it makes the most sense to reuse POCOs and when it makes more sense to separate intentions.

推荐答案

基于消息的 API 设计

在设计理想的基于消息的 API 时,需要牢记一些注意事项,您的服务最终可以有效地为 2 个主服务器提供服务:一个本地客户端 API 和一个 REST API.本机客户端 只是以原始形式发送和接收消息,以便他们获得一个免费的自然 API,使用 C# 请求和响应 DTO 建模,以捕获服务执行其操作所需的信息以及它应该返回的信息.

Message-based API Design

There are a few things to bear in mind when designing the ideal message-based API where your Services effectively end up serving 2 masters: a Native Client API and a REST API. Native Clients just send and receive messages in their original form so they get a natural API for free modelled using C# Request and Response DTOs to capture what information is required for the Service to perform its Operation and what it should return.

在设计基于消息的 API 之后,您需要关注如何最好地将消息投射到 REST API 中,方法是使用 [Route] 注释请求 DTO用于定义服务的自定义端点的属性.

After designing your message-based API you'll then want to focus on how best to project the messages into a REST API by annotating Request DTOs with [Route] Attributes to define the Custom endpoints for your Services.

之前关于 使用 ServiceStack 设计 REST-ful 服务 的答案提供了不同请求 DTO 映射到的路由示例,通常,您会希望围绕 Resources 设计 API,其中每个操作作用于资源",这将使定义自定义路由更容易.用于创建和更新预订限制的理想 HTTP API 如下所示:

This previous answer on Designing a REST-ful service with ServiceStack provides examples on which routes different Request DTOs map to, in general you'll want to design your APIs around Resources where each operation "acts on a Resource" which will make defining your Custom Routes easier. The ideal HTTP API for Creating and Updating a Booking Limit would look like:

POST /bookinglimits       (Create Booking Limit)
PUT  /bookinglimits/{id}  (Update Booking Limit)

关于良好 API 设计的一般建议

这篇关于良好 API 设计的十项规则的文章虽然不是专门关于 Web 服务的,但提供了关于通用(代码或服务)API 设计.由于 API 使用者是您的 API 的目标受众,他们将主要从中获得最大价值,因此应优化他们的设计,使其具有自我描述性、使用一致的命名、使用直观且可以在不中断的情况下不断发展现有客户.消息自然适合版本控制,但在对现有发布的 API 进行更改时,您仍然需要注意任何其他属性都是可选的如果需要,具有默认回退行为.

General recommendations on good API Design

Whilst not specifically about Web Services this article on Ten Rules for Good API Design provides good recommendations on general (Code or Services) API design. As API Consumers are the intended audience of your APIs who'll primarily be deriving the most value from them, their design should be optimized so that they're self-descriptive, use consistent naming, are intuitive to use and can be evolved without breaking existing clients. Messages are naturally suited to versioning but you still need to be mindful when making changes to existing published APIs that any additional properties are optional with default fallback behavior if required.

出于这个原因,虽然您可以通过返回裸 BookingLimit 来节省一些代码,但我更喜欢为每个服务返回一个特定的响应 DTO,这允许服务返回额外的元数据而不会破坏现有客户端同时为所有服务保持一致的请求/响应模式.虽然这只是我的偏好 - 返回裸类型也可以.

For this reason whilst you can save some code by returning a naked BookingLimit, my preference is to instead return a specific Response DTO for each Service which allows the Service to return additional metadata without breaking existing clients whilst maintaining a consistent Request/Response pattern for all Services. Although this is just my preference - returning naked types is also fine.

为了在 ServiceStack 中实现这一点,我不会使用相同的请求 DTO 来支持多个动词.由于请求 DTO 被称为 Create*,它表明用户应该只将此请求 DTO 发送到创建预订限制,这通常使用 POST 请求完成,例如:

To implement this in ServiceStack I wouldn't use the same Request DTO to support multiple verbs. Since the Request DTO is called Create* that conveys that users should only send this Request DTO to Create Booking limits which is typically done using a POST request, e.g:

[Route("/bookinglimits", "POST")]
public class CreateBookingLimit : IReturn<CreateBookingLimitResponse>, IPost
{      
  public int ShiftId { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
  public int Limit { get; set; } 
}

public class CreateBookingLimitResponse
{
    public BookingLimit Result { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}

IPutIPost动词接口标记,它让用户和服务客户​​端都知道应该使用哪个动词发送此消息,这使得可以在单个服务网关方法.

The IPut, IPost are Verb interface markers which lets both the User and Service Client know which Verb this message should be sent with which makes it possible to have all messages sent in a single Service Gateway method.

如果您的服务还支持更新预订限制,那么我将为它创建一个单独的服务,如下所示:

If your Service also supports updating a Booking Limit then I'd create a separate Service for it which would look like:

[Route("/bookinglimits/{Id}", "PUT")]
public class UpdateBookingLimit : IReturn<UpdateBookingLimitResponse>, IPut
{      
  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; } 
}

public class UpdateBookingLimitResponse
{
    public BookingLimit Result { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}

通过使用单独的操作,您可以确保请求 DTO 仅包含与该操作相关的属性,从而减少 API 使用者的混淆.

By using separate Operations you can ensure Request DTOs contains only the properties relevant to that operation, reducing the confusion for API consumers.

如果它对您的服务有意义,例如两个操作的模式保持不变,我将把两个创建/更新操作合并到一个操作中.当您这样做时,您应该使用一致的动词来指示操作何时同时执行,例如Store*CreateOrUpdate*:

If it makes sense for your Service, e.g. the schemas for both operations remains the same I'll merge both Create/Update operations into a single Operation. When you do this you should use a consistent Verb that indicates when an operation does both, e.g. Store* or CreateOrUpdate*:

[Route("/bookinglimits", "POST")]
public class StoreBookingLimit : IReturn<StoreBookingLimitResponse>, IPost
{      
  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; } 
}

public class StoreBookingLimitResponse
{
    public BookingLimit Result { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}

在服务器为资源生成 Id 的大多数情况下,您应该使用 POST,在客户端指定 Id 的极少数情况下,例如SlugGuid 你可以使用 PUT 粗略地翻译成把这个资源放在这个位置",这在客户端知道 URL 时是可能的资源.

In most cases where the Server generates the Id for the Resource you should use POST, in the rare case where the client specifies the Id, e.g. Slug or Guid you can use PUT which roughly translates to "PUT this resource at this location" which is possible when the client knows the url for the resource.

大多数情况下,消息应包含的内容根据服务要求是显而易见的,并且随着时间的推移变得直观和自然.有关基于消息的综合 API 的示例,您可以查看 AWS Web 服务,他们在基于消息的设计背后有效地服务了他们的 Web 服务,该设计使用服务客户端发送消息以访问其所有 API,例如AWS DynamoDB API Reference 列出了每个可用的操作以及服务返回的其他 DTO 类型,例如这里是他们在创建/修改和查询项目方面拥有的 DynamoDB API:

Most of the time what messages should contain will be obvious based on the Service requirements and becomes intuitive and natural to create over time. For examples on a comprehensive message-based API you can have a look AWS Web Services who've effectively servicified their Web Services behind a message-based design that uses Service Clients to send messages to access all their APIs, e.g. AWS DynamoDB API Reference lists each Actions that's available as well as other DTO Types that the Services return, e.g here are DynamoDB APIs they have around Creating / Modifying and Querying Items:

  • BatchGetItem
  • BatchWriteItem
  • 删除项目
  • 获取项目
  • 放置项
  • 查询
  • 扫描
  • 更新项目
  • 属性定义
  • 属性值
  • 属性值更新
  • 条件
  • ...

在 ServiceStack 中,操作称为 操作,您将使用请求 DTO 定义什么,而 AWS 数据类型仅称为 DTO,我将其保存在 Types 命名空间中区别于运营.

In ServiceStack Actions are called Operations and what you'll use Request DTOs to define, whilst AWS Data Types are just called DTOs which I keep in a Types namespace to differentiate from Operations.

DynamoDb.ServiceModel (project)

/GetItem
/PutItem
/UpdateItem
/DeleteItem
/Query
/Scan

/Types 
  /AttributeDefinition
  /AttributeValue
  /AttributeValueUpdate

您通常不需要为批量请求提供额外的显式服务,因为您可以使用 ServiceStack 的 自动批量请求.ServiceStack 还包括许多其他好处,它能够在源 DTO 中生成包含自定义属性和接口的更丰富的 DTO,以启用 更丰富和简洁的端到端类型化 API 需要更少的样板和生成的代码,让您可以使用相同的泛型服务客户端调用任何提供同步和惯用异步 API 的 ServiceStack 服务.额外的元数据还支持无缝的高级功能,例如 加密消息缓存感知客户端、多种格式服务网关, HTTP 动词接口标记

You typically wouldn't need additional explicit Services for Batch Requests as you can get that for free using ServiceStack's Auto Batched Requests. ServiceStack also includes a number of other benefits where it's able to generate richer DTOs containing Custom Attributes and interfaces in the Source DTOs to enable a richer and succinct end-to-end typed API requiring less boilerplate and generated code that lets you use the same Generic Service Client to call any ServiceStack Service offering both Sync and idiomatic Async APIs. The additional metadata also enables seamless higher-level functionality like Encrypted Messaging, Cache Aware Clients, Multiple Formats, Service Gateway, HTTP Verb Interface Markers, etc.

否则 AWS 遵循与 ServiceStack 非常相似的方法来设计基于消息的 API,使用 泛型服务客户端发送每种语言的原生DTO.

Otherwise AWS follows a very similar approach to ServiceStack for designing message-based APIs using generic Service Clients to send DTOs native in each language.

这篇关于更多 ServiceStack 请求 DTO 建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆