推荐的ServiceStack API结构

我正在尝试构build我们的API的最佳方式; 我们有评论,我们已经build立了一个标准的REST结构(列表一,列出所有,创build,更新等)。 不适合的例子是:每个评论可以链接到一个或多个其他types,例如事件,位置或事物。

我的想法是这些url将沿着:/事件/评论/(或这个例如/评论/事件/相反)/位置/评论/ /事情/评论/

但是,我可以看到的问题是每个这些“GET”应返回父对象,即一个事件。

所以使用ServiceStack,处理这种情况的最好方法是什么? 它是为每个数据请求创build一个自定义服务,而不是滥用开箱即用的REST设置,或者我错过了更基本的东西?

首先“最佳”解决scheme是一个相当主观的术语。 我通常会瞄准DRY,可重复使用,高性能的解决scheme,以促进最小的努力,摩擦和讨厌,而其他人可能会定义“最佳”,它遵循REST的原则。 所以你会得到不同的回应,这取决于目标是什么。 我只能提供我将如何处理它。

ServiceStack服务实现从它们的自定义路由中分离出来

有一件事要记住,你如何在ServiceStack中定义和devise你的服务,在你如何公开你的服务方面是相当分离的,因为你可以在任何自定义的路由下公开你的服务。 ServiceStack鼓励基于消息的devise,所以你应该给每个操作一个不同的信息。

使用逻辑/分层Url结构

我会使用一个合乎逻辑的Url结构来表示一个名词的标识符,这个名词是分层结构化的,也就是说父path对你的资源进行分类,并给它一个有意义的上下文。 所以在这种情况下,如果你想揭露事件和评论我的倾向是去以下的url结构:

/events //all events /events/1 //event #1 /events/1/reviews //event #1 reviews 

这些资源标识符中的每一个都可以应用任何HTTP动词

履行

对于实现,我通常遵循基于消息的devise,并根据响应types和调用上下文对所有相关的操作进行分组。 为此,我会做这样的事情:

 [Route("/events", "GET")] [Route("/events/category/{Category}", "GET")] //*Optional top-level views public class SearchEvents : IReturn<SearchEventsResponse> { //Optional resultset filters, eg ?Category=Tech&Query=servicestack public string Category { get; set; } public string Query { get; set; } } [Route("/events", "POST")] public class CreateEvent : IReturn<Event> { public string Name { get; set; } public DateTime StartDate { get; set; } } [Route("/events/{Id}", "GET")] [Route("/events/code/{EventCode}", "GET")] //*Optional public class GetEvent : IReturn<Event> { public int Id { get; set; } public string EventCode { get; set; } //Alternative way to fetch an Event } [Route("/events/{Id}", "PUT")] public class UpdateEvent : IReturn<Event> { public int Id { get; set; } public string Name { get; set; } public DateTime StartDate { get; set; } } 

并按照事件评论类似的模式

 [Route("/events/{EventId}/reviews", "GET")] public class GetEventReviews : IReturn<GetEventReviewsResponse> { public int EventId { get; set; } } [Route("/events/{EventId}/reviews/{Id}", "GET")] public class GetEventReview : IReturn<EventReview> { public int EventId { get; set; } public int Id { get; set; } } [Route("/events/{EventId}/reviews", "POST")] public class CreateEventReview : IReturn<EventReview> { public int EventId { get; set; } public string Comments { get; set; } } 

实现应该是相当直接的基于这些消息,这将取决于代码库的大小,我将组织2 EventsServiceEventReviewsService类。 我应该注意到我使用服务请求DTO名称的复数forms来避免与同名的数据模型冲突。

虽然我在这里分开了UpdateEventCreateEvent ,但是如果用例允许,我有时会把它们合并成一个幂等的StoreEvent操作。

物理项目结构

理想情况下,根级AppHost项目应该保持轻量级和免执行。 尽pipe对于只有less数服务的小型项目来说,一切项目都可以在单个项目中进行,并根据需要简单地增加架构。

对于大中型项目,我们推荐下面的物理结构,为了这个例子的目的,我们假定我们的应用程序叫做EventMan

项目的顺序也显示其依赖关系,例如顶级EventMan项目引用所有子项目,而最后一个EventMan.ServiceModel项目引用none

 - EventMan AppHost.cs // ServiceStack ASP.NET Web or Console Host Project - EventMan.ServiceInterface // Service implementations (akin to MVC Controllers) EventsService.cs EventsReviewsService.cs - EventMan.Logic //For larger projs: pure C# logic, data models, etc IGoogleCalendarGateway //Eg of a external dependency this project could use - EventMan.ServiceModel //Service Request/Response DTOs and DTO types Events.cs //SearchEvents, CreateEvent, GetEvent DTOs EventReviews.cs //GetEventReviews, CreateEventReview Types/ Event.cs //Event type EventReview.cs //EventReview type 

通过将EventMan.ServiceModel DTO保存在自己独立的实现和无依赖的dll中,您可以自由地在任何.NET客户端项目中共享此dll – 您可以将其与任何通用C#服务客户端一起使用提供一个没有任何代码的端到端types的API。


更新

  • 这个推荐的项目结构现在包含在所有的ServiceStackVS的VS.NET模板中 。

  • 简单客户REST示例使用RDBMS创build一个简单的REST服务的一个小型自包含的真实示例。

不知道这是否会帮助你的情况/理解,但我觉得这个演示文稿有帮助:

devise一个漂亮的REST + JSON API