2013-05-10 90 views
3

我一直在试验ServiceStack框架来开发一个简单的REST API。我遇到了麻烦,试图正确定义路由来处理我期望的不同网址。如何将多个请求DTO映射到单个路由

我有一个简单的DomainModel类:

public class Student 
{ 
    public int Id { get; set; } // unique 
    public string Email { get; set; } // not unique 

    // some other properties and business logic 
} 

我想创造出响应HTTP请求到以下网址REST服务:

  • /students
    • GET返回所有学生
  • /students/123
    • GET返回学生使用id = 123
  • /students?id=123
    • GET返回学生使用id = 123
  • /[email protected]
    • GET返回所有的学生与匹配的电子邮件

我曾尝试使用下面的请求的DTO来完成这项尝试:

[Route("/students", "GET")] 
public class GetAllStudents : IReturn<StudentList> 
{ 
} 

[Route("/students", "GET")] // I want this to be for /students?Id= 
[Route("/students/{Id}", "GET")] 
public class GetStudentById : IReturn<Student> 
{ 
    public int Id { get; set; } 
} 

[Route("/students", "GET")] // I want this to be for /students?Email= 
public class GetStudentsByEmail : IReturn<StudentList> 
{ 
    public string Email { get; set; } 
} 

正如你所看到的,我只是想用两种不同的反应的DTO:

public class StudentList : List<Student> 
{ 
} 

public class Student 
{ 
    public int Id { get; set; } 
    public String Email { get; set; } 
} 

注:这个Reponse DTO Student类与我的DomainModel类是分开的;他们在不同的命名空间。

不幸的是,当我尝试使用这些路线时,对/students?<anything>的每个请求最终都会返回所有学生。唯一能够工作的路由是,如果我向/students/123发出GET请求,那么我将Id 123返回给Student。我认为这不起作用,因为我正在将多个Request DTO的"/students"路由定义重新使用。

我一直在阅读ServiceStack wikiexamples,但我无法弄清楚如何完成我所尝试的。我可以找到关于高级路由的最详细的文档是"Smart Routing" section of the "New API" page,但它并没有真正解决这种情况。

如何重新使用多个请求DTO的相同路由定义?

+0

我不确定你可以按照你想要的方式做到这一点。我可以建议路线'/学生/ {Id}'作为替代方案吗? – rossipedia 2013-05-10 19:58:44

+0

@rossipedia即使我摆脱了'/ students?id = 123'的路由,我仍然有'GetAllStudents'和'GetStudentsByEmail'重复路由定义的问题。老实说,我不需要''id ='路线,但是摆脱它不会让我更进一步。也许我误解了你的建议?你能在答案中提供更多细节吗? – 2013-05-10 20:04:57

+0

请参阅下面的@ mythz的答案。他解释得比我更好:) – rossipedia 2013-05-10 20:11:11

回答

5

在您的请求中有ByXXX后缀DTO是ServiceStack中的代码异味,他鼓励设计基于消息的粗粒度接口。请参阅How to design a Message-Based API with ServiceStack这更早的答案,为什么你应该响应类型调用语义

在这种情况下,你有一个服务做的一个关于独特标识一个Get返回单个学生组服务和你也希望有一个Search电子邮件返回多个学生。因此,在这种情况下,我将有以下服务:

[Route("/students/{Id}")] 
public GetStudent : IReturn<Student> 
{ 
    public int Id { get; set; } 
} 

这将处理只是/students/123

[Route("/students")] 
public FindStudents : IReturn<List<Student>> 
{ 
    public int? Id { get; set; } 
    public string Email { get; set; } 
} 

哪些可以用来处理:

虽然我个人并不包括Id在这里,因为它是一个获取代替过滤

+0

我一开始就是这样做的,根据你在那个环节的回答。我不喜欢我的Service方法中需要一堆'if'逻辑来确定用户正在搜索的内容。例如,如果我也想为我的'FindStudents' RequestDTO添加'Birthday',那么我的Service方法需要执行以下逻辑:*“是Id集?是电子邮件集?是生日集?如果Birthday不匹配Id?etc。“*我试图保留更小,更集中的服务方法,例如”Get(StudentsByEmail请求)“,但我可能会试图在这里”打架“,这是我不想做的。我将尝试更多... – 2013-05-10 20:22:56

+0

...感谢您的答案和酷框架顺便说一句! – 2013-05-10 20:23:21

+1

@JesseWebb请注意if逻辑应该是您用来构建内部查询或过滤器的内容,因此可以使用任意过滤器组合来调用相同的服务。 – mythz 2013-05-10 20:29:32

相关问题