我想了解在根据REST设计HTTP GET响应时应遵循哪种方法。我有以下要求
class Employee {
private long employeedID;
private String name;
private Date dob;
private String address;
private String department;
}
根据REST建模,HTTP GET / employees将返回所有员工的数组。类似地,HTTP GET / employees / 1将返回Id为1的员工
现在有一个UI驱动的工作流程,我需要只显示每个员工的名称和 employeeID 。因此,HTTP GET /员工的现有响应是重量级的(其他字段是不必要的转移)。因此,我希望将响应限制为仅包含每位员工的名称和 employeeID 。
我正在评估以下选项
方法1:
使用Content-Type HTTP标头指示发出HTTP GET / employees请求的客户端需要在响应中修剪属性列表。我在Content-Type(即application.summary + json)中有一些自定义字符串,这将导致只有2个属性被包含在响应中
方法2:
使用其他查询参数作为HTTP GET / employess?isSummary = true。在这种情况下,在服务器端,根据 isSummary 参数的值,我只能为每个员工返回2个属性
方法3:
创建一个新的REST端点本身,支持修剪后的响应,即HTTP GET / employees / summaryDetails
在这种情况下,在上述端点中仅返回2个属性。
这三种方法中哪一种最接近REST?
由于
答案 0 :(得分:2)
我认为方法#2 领域的某些方面是这里的方法。从根本上说,您仍然在资源(Employee)方面访问相同的搜索和结果集,并且它是相同的资源。所以方法#3不太适合。
也就是说,有很多方法可以解决#2。一种方法是使用表示投影的查询字符串参数 - 类似于SQL投影。如下所示:
GET /employees?fields=ID,name
我使用了一些以这种方式工作的API,并且它们运行良好。
答案 1 :(得分:1)
此答案作为以下评论this回答中的讨论的后续行动添加。
基本上,是的,我反对HATEOAS。为什么?一般来说这个想法很好,但是:
IMO在涉及端点数量时往往会删除合理的限制。似乎某些开发人员的回答/data/{id}/add/
,将通过_links
元字段进行记录。这不是应该怎么做的。这样,您始终可以添加新的端点和适当的链接,并完成大量无法理解或验证的端点。例如。此链接返回基本数据集:
"http://foo.bar/employees/1"
这将返回更多细节:
"http://foo.bar/employees/1/details"
如果我需要其他细节子集怎么办?我会添加一个新的端点吗?并且..如果有多个不同的客户需要互斥,该怎么办? 数据子集?每个客户端都有一个专用端点?这是一场噩梦!
链接不仅仅是关于URL,也是查询参数。它们是否包含在链接中?以什么形式?模板?所以我不能按原样关注链接。每个参数都有一个默认值?我想这不是简单的可能为每个查询参数提供默认值。
上述可发现性和文档。相信我,对于您设计,开发和部署的大多数API,您需要编写文档。为什么?因为订购此API的公司需要它。 stripe.com遵循HATEOS规则吗?没有!那为什么它如此成功?因为它非常好documented并且有多个库以及多种最流行的语言和工具中的示例。
找时间查看this对话,这是值得的。
现在关于HATEOAS的简短注释之后。
方法#1
当资源版本更改(添加或删除新字段)本身而不是您需要特定字段或资源子集时,应使用标头。所以IMO不是这样的。
方法#3
对于这个答案的介绍中提到的原因,这是一个非常糟糕的主意。
方法#2
恕我直言,这是要走的路。正如@leeor所说,这是一种受欢迎的,被接受的和灵活的模式。
您可以通过添加一个名为eg的查询参数来扩展它。 view
这是一个枚举(SIMPLE
,EXTENDED
,FULL
),代表预定义视图的列表。这是避免添加新端点的方法。而是添加并记录(!)新视图。如果view
和fields
相互排斥或处理它们的顺序,则取决于您。
答案 2 :(得分:0)
每种列出的方法的问题在于它使API复杂化,并且可能违反了REST的最基本原则,即可发现性。响应没有提供任何上述API存在的线索。你必须阅读文档(恐怖!)。 REST的基本规则是HATEOAS:超文本作为应用程序状态的引擎。
因此,如果您想要一个最大 RESTful的API,请考虑以下内容,该标准遵循HAL标准:
此:
HTTP GET /employees
的产率:
[ {
"employeeID": 1,
"name": "Joe",
"_links": [ {
"rel": "self",
"href": "http://foo.bar/employees/1"
}, {
"rel": "details",
"href": "http://foo.bar/employees/1/details"
} ]
}, {
"employeeID": 2,
"name": "Sam",
"_links": [ {
"rel": "self",
"href": "http://foo.bar/employees/2"
}, {
"rel": "details",
"href": "http://foo.bar/employees/2/details"
} ]
} ]
点击链接:
HTTP GET /employees/1
的产率:
{
"employeeID": 1,
"name": "Joe",
"_links": [ {
"rel": "self",
"href": "http://foo.bar/employees/1"
}, {
"rel": "details",
"href": "http://foo.bar/employees/1/details"
} ]
}
关注另一个链接:
HTTP GET /employees/1/details
的产率:
{
"employeeID": 1,
"name": "Joe",
"dob": "1985-04-23",
"address": "123 Main St",
"department": "Department of Redundant Links",
"_links": [ {
"rel": "self",
"href": "http://foo.bar/employees/1"
}, {
"rel": "details",
"href": "http://foo.bar/employees/1/details"
} ]
}
要获得灵感,请查看JIRA REST API,可能是我见过的最好的。{/ p>