推荐的 ServiceStack API 结构 [英] Recommended ServiceStack API Structure

查看:46
本文介绍了推荐的 ServiceStack API 结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试找出构建 API 的最佳方式;我们在标准 REST 结构中设置了评论(列出一个、列出所有、创建、更新等).它不太适合示例的地方是:每个评论都可以链接到一个或多个其他类型,例如事件、地点或事物.

I'm trying work out the best way to structure our API; we have Reviews which we've setup in a standard REST structure (list one, list all, create, update etc). Where it doesn't quite fit the examples is: each review can be linked to one or more other types e.g. Event, Location or Thing.

我的想法是网址应该是:/event/reviews/(或与此相反,例如/reviews/event/)/位置/评论//东西/评论/

My thinking is the urls would be along the lines of: /event/reviews/ (or the reverse of this e.g. /reviews/event/) /location/reviews/ /thing/reviews/

然而,我可以看到的问题是每个这些的GET"应该返回父对象,即一个事件.

The issue I can see however is the "GET" for each of these should return the parent object i.e. an Event.

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

So using ServiceStack, what's the best way to handle this scenario? Is it to create a custom service for each data request rather than abusing the out-of-the-box REST setup or have I missed something more fundamental?

推荐答案

首先,最佳"解决方案是一个相当主观的术语.我通常会瞄准 DRY、可重用、高性能的解决方案,以促进最少的努力、摩擦和健谈,而其他人可能会根据它遵循 REST 原则的程度来定义最佳".因此,根据目标的不同,您会得到不同的回应.我只能提供我将如何处理它.

Firstly "Best" solution is a fairly subjective term. I'll generally aim for DRY, re-usable, performant solutions that promotes the least effort, friction and chattiness, whilst others may define "Best" in how closely it follows the principles of REST. So you will get varied responses depending on what the goals are. I can only offer how I would approach it.

要记住的一件事是,您在 ServiceStack 中定义和设计服务的方式与公开它们的方式相当分离,因为您可以在任何自定义路由下公开您的服务.ServiceStack 鼓励基于消息的设计,因此您应该为每个操作提供不同的消息.

One thing to keep in mind is how you define and design your services in ServiceStack are fairly de-coupled in how you expose them, since you can expose your services under any custom route. ServiceStack encourages a message-based design so you should give each operation a distinct message.

我会使用一个逻辑 Url 结构来表示一个名词的标识符,它是分层结构的,即父路径对您的资源进行分类并为其提供有意义的上下文.因此,在这种情况下,如果您想公开事件和评论,我倾向于使用以下网址结构:

I'd use a logical Url structure that I aim to represent the identifier of a noun, which is hierarchically structured, i.e. the parent path categorizes your resource and gives it meaningful context. So in this case if you wanted to expose Events and reviews my inclination is to go with following url structure:

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

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

Each of these resource identifiers can have any HTTP Verb applied to them

对于实现,我通常遵循基于消息的设计,并根据响应类型和调用上下文对所有相关操作进行分组.为此,我会做类似的事情:

For the implementation I generally follow a message-based design and group all related operations based on Response type and call context. For this I would do something like:

[Route("/events", "GET")]
[Route("/events/category/{Category}", "GET")] //*Optional top-level views
public class SearchEvents : IReturn<SearchEventsResponse>
{
   //Optional resultset filters, e.g. ?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; }
}

并遵循类似的活动评论模式

And follow a similar pattern for Event reviews

[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 名称使用了复数形式,以避免与同名数据模型发生冲突.

The implementation should be fairly straight forward based on these messages, which (depending on code-base size) I would organize in 2 EventsService and EventReviewsService classes. I should note that I use pluralization for Service Request DTO names myself to avoid clashing with data models of the same name.

虽然我在此处将 UpdateEventCreateEvent 分开,但有时我会将它们合并为单个幂等的 StoreEvent 操作,如果使用 -案件许可.

Although I've separated UpdateEvent and CreateEvent here, I will sometimes will merge them into a single idempotent StoreEvent operation if the use-case permits.

理想情况下,根级 AppHost 项目应保持轻量级且无需实现.尽管对于只有少数服务的小型项目,可以将所有内容都放在一个项目中,并在需要时根据需要简单地扩展您的架构.

Ideally the root-level AppHost project should be kept lightweight and implementation-free. Although for small projects with only a few services it's ok for everything to be in a single project and to simply grow your architecture when and as needed.

对于大中型项目,我们推荐以下物理结构,为了本示例的目的,我们假设我们的应用程序名为 EventMan.

For medium-to-large projects we recommend the physical structure below which for the purposes of this example we'll assume our Application is called EventMan.

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

The order of the projects also show its dependencies, e.g. the top-level EventMan project references all sub projects whilst the last EventMan.ServiceModel project references 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  //E.g 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# 服务客户端一起使用以提供端到端-end 类型的 API,没有任何代码生成.

With the EventMan.ServiceModel DTO's kept in their own separate implementation and dependency-free dll, you're freely able to share this dll in any .NET client project as-is - which you can use with any of the generic C# Service Clients to provide an end-to-end typed API without any code-gen.

简单客户 REST 示例 有一个独立的、真实的小型示例,用于创建一个简单的使用 RDBMS 的 REST 服务.

The Simple Customer REST Example has a small self-contained, real-world example of creating a simple REST Service utilizing an RDBMS.

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

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