[英]Recommended ServiceStack API Structure
I'm trying work out the best way to structure our API; 我正在尝试找出构建API的最佳方法; we have Reviews which we've setup in a standard REST structure (list one, list all, create, update etc).
我们在标准REST结构中设置了评论(列表一,列出所有,创建,更新等)。 Where it doesn't quite fit the examples is: each review can be linked to one or more other types eg Event, Location or Thing.
在不完全符合示例的情况下:每个评论可以链接到一个或多个其他类型,例如事件,位置或事物。
My thinking is the urls would be along the lines of: /event/reviews/ (or the reverse of this eg /reviews/event/) /location/reviews/ /thing/reviews/ 我的想法是网址将是:/ event / reviews /(或相反的例如/ reviews / event /)/ location / reviews / / thing / reviews /
The issue I can see however is the "GET" for each of these should return the parent object ie an Event. 然而,我可以看到的问题是每个这样的“GET”应该返回父对象,即一个事件。
So using ServiceStack, what's the best way to handle this scenario? 那么使用ServiceStack,处理这种情况的最佳方法是什么? 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?
是为每个数据请求创建一个自定义服务而不是滥用开箱即用的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.
我通常的目标是干燥,可重复使用,高性能的解决方案,促进最小的努力,摩擦和chattiness,而其他人可能会定义“最佳”,它遵循REST的原则。 So you will get varied responses depending on what the goals are.
因此,根据目标的不同,您将获得不同的响应。 I can only offer how I would approach it.
我只能提供如何处理它。
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中定义和设计服务的方式与您公开它们的方式完全脱离,因为您可以在任何自定义路径下公开您的服务。 ServiceStack encourages a message-based design so you should give each operation a distinct message.
ServiceStack鼓励基于消息的设计,因此您应该为每个操作提供不同的消息。
I'd use a logical Url structure that I aim to represent the identifier of a noun, which is hierarchically structured, ie the parent path categorizes your resource and gives it meaningful context. 我使用逻辑Url结构,我的目标是表示名词的标识符,它是分层结构的,即父路径对您的资源进行分类并为其提供有意义的上下文。 So in this case if you wanted to expose Events and reviews my inclination is to go with following url structure:
因此,在这种情况下,如果您想公开事件和评论,我倾向于使用以下url结构:
/events //all events
/events/1 //event #1
/events/1/reviews //event #1 reviews
Each of these resource identifiers can have any HTTP Verb applied to them 这些资源标识符中的每一个都可以应用任何HTTP谓词
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; }
}
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. 基于这些消息,实现应该是相当直接的,这些消息(取决于代码库大小)我将在2个EventsService和EventReviewsService类中组织。 I should note that I use pluralization for Service Request DTO names myself to avoid clashing with data models of the same name.
我应该注意,我自己使用多个服务请求DTO名称,以避免与同名的数据模型发生冲突。
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. 虽然我在这里分离了
UpdateEvent
和CreateEvent
,但如果用例允许,我有时会将它们合并到一个幂等的StoreEvent
操作中。
Ideally the root-level AppHost project should be kept lightweight and implementation-free. 理想情况下,根级AppHost项目应保持轻量级且无实现。 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.
虽然对于只有少量服务的小型项目,可以将所有内容都放在一个项目中,并根据需要简单地扩展您的架构。
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 。
The order of the projects also show its dependencies, eg the top-level EventMan
project references all sub projects whilst the last EventMan.ServiceModel
project references none : 项目的顺序也显示其依赖关系,例如顶级
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 //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
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. 通过将
EventMan.ServiceModel
DTO保存在各自独立的实现和无依赖dll中,您可以自由地在任何.NET客户端项目中共享此dll,您可以将其与任何通用C#服务客户端一起使用提供端到端类型的API,没有任何代码。
This recommended project structure is now contained in all ServiceStackVS' VS.NET Templates . 此推荐的项目结构现在包含在所有ServiceStackVS的VS.NET模板中 。
The Simple Customer REST Example has a small self-contained, real-world example of creating a simple REST Service utilizing an RDBMS. 简单客户REST示例有一个小型的自包含,真实世界的例子,用于使用RDBMS创建简单的REST服务。
Not sure if it will help in your scenario/understanding, but I find this presentation helpful: 不确定它是否有助于你的场景/理解,但我发现这个演示文稿很有帮助:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.