Ale*_*lex 30 rest api-design conceptual
这个问题是关于最佳REST API设计和我在嵌套资源和根级别集合之间选择的问题.
为了说明这个概念,假设我有收藏City,Business和Employees.典型的API可以如下构造.想象一下,ABC,X7N和WWW是关键,例如guids:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
Run Code Online (Sandbox Code Playgroud)
这看起来很干净,因为它遵循原始域结构 - 业务在城市,员工在公司.单个项目可通过集合下的密钥访问(例如,../Businesses返回所有业务,同时../Businesses/X7N返回单个业务).
以下是API消费者需要做的事情:
(GET Api/City/ABC/Businesses)(GET Api/City/ABC/Businesses/X7N/Employees)(PUT Api/City/ABC/Businesses/X7N/Employees/WWW)第二次和第三次调用虽然看起来在正确的位置,但使用了许多实际上不必要的参数.
X7N)的关键.WWW)后端代码中的任何内容都不需要非关键信息来查找业务或更新员工.因此,相反,以下端点看起来更好:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我已经为企业和员工创建了一个新的根,即使从域的角度来看,它们也是一个子/子子集合.
这两种解决方案对我来说都不是很干净.
POST Api/Businesses/X7N7/Employees,这会使一切更加混乱.有没有更清洁,第三种方式,我没有想到?
eds*_*ufi 22
我没有看到REST如何添加一个约束,即两个资源不能具有相同的值.这resourceType/ID只是最简单的用例的一个例子,而不是从RESTful角度出发的最佳方式.
如果您仔细阅读Roy Fielding论文的第5.2.1.1段,您会注意到Fielding在价值和资源之间进行了区分.现在资源应该有一个唯一的URI,这是真的.但没有什么能阻止两个资源具有相同的价值:
例如,学术论文的"作者'首选版本"是其值随时间变化的映射,而对"在会议X的会议论文中发表的论文"的映射是静态的.这是两个不同的资源,即使它们在某个时间点都映射到相同的值.区分是必要的,以便可以独立地识别和引用这两种资源.软件工程中的一个类似示例是在引用"最新版本","版本号1.2.7"或"橙色版本中包含的修订版"时单独标识版本控制的源代码文件.
所以没有什么可以阻止你,正如你所说,改变根.在您的示例中,a Business是值而不是资源.创建一个资源是完美的RESTful,这是一个"位于城市中的每个企业"的列表(就像Roy的例子,"橙色版本中包含的修订"),同时拥有"ID为x的资源"资源(如"修订号x").
因为Employees,我会保持API/Businesses/X7N/Employees一个企业和它的员工之间的关系是一个组合关系,因此,正如你所说,Employees可以而且应该只能通过Businesses类根访问.但这不是REST要求,另一种选择也是RESTful.
请注意,这与HATEAOS原则的应用是一致的.在您的API中,位于城市中的企业列表可以(也许应该从理论的角度来看)只是一个链接列表API/Businesses.但这意味着客户端必须为列表中的每个项目进行一次往返服务器.这样做效率不高,为了保持务实,我所做的就是将业务的表示形式与self此示例中的URI链接一起嵌入到列表中API/Businesses.
nep*_*dev 13
您不应该将REST与特定URI命名约定的应用程序混淆.
如何命名资源完全是次要的.您正在尝试使用HTTP资源命名约定 - 这与REST无关.罗伊·菲尔丁本人在其他人引用的文件中反复说明.REST不是协议,它是一种架构风格.
事实上,Roy Fielding在2008年的博客评论中指出(http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven 6/20/2012):
"REST API不能定义固定资源名称或层次结构(客户端和服务器的明显耦合).服务器必须能够自由控制自己的命名空间.相反,允许服务器指示客户端如何构造适当的URI,例如通过在媒体类型和链接关系中定义这些指令,在HTML表单和URI模板中完成."
所以本质上:
您描述的问题实际上并不是REST的问题 - 从概念上讲,它是层次结构与关系结构的问题.
虽然企业"在"一个城市,因此可以被视为城市"等级"的一部分 - 那么在75个城市设有办事处的国际公司呢?然后,城市突然成为层次结构中的初级元素,其中商业名称位于结构的高级层次.
关键是,您可以从各个角度查看数据,并且根据您所采用的视点,将其视为层次结构可能最简单.但是相同的数据可以看作是具有不同级别的层次结构.使用HTTP类型资源名称时,您已输入HTTP定义的层次结构.这是一个约束,是的,但它不是REST约束,它是HTTP约束.
从这个角度来看,您可以选择更适合您场景的解决方案.如果您的客户在提供公司名称(他可能不知道)时无法提供城市名称,那么最好只使用城市名称的密钥.正如我所说,这取决于你,REST不会阻挡你...
更重要的是:
如果您已经决定将HTTP与GET PUT一起使用,那么您拥有的唯一真正的REST约束是:
Look at your proposal #1 above in that light. You assume that customers know the keys for the cities which are contained in your system? Wrong - that's not restful. So the server has to give the list of cities as a list of choices in some way. So are you going to list every city in the world here? I guess not, but then you'll have to do some work on how you are planning to do this, which brings us to:
I think, reading the mentioned Roy Fielding blog will help you out considerably.
在 RESTful-API URL 设计中应该是不重要的——或者至少是一个附带问题,因为可发现性是在超文本中编码的,而不是在 URL 路径中。在 StackOverflow 上查看REST 标签 wiki 中链接的资源。
但是如果你想为你的 UC 设计人类可读的 URL,我建议如下:
使用您正在创建/更新/查询的资源类型作为 URL 的第一部分(在您的 API 前缀之后)。因此,当有人看到 URL 时,他立即知道此 URL 指向哪些资源。 GET /Api/Employees...是从 API 接收员工资源的唯一方法。
为每个资源使用唯一 ID,独立于它们所处的关系。所以GET /Api/<CollectionType>/UniqueKey应该返回一个有效的资源表示。没有人应该担心 Employee 的位置。(但返回的 Employee 应该有他所属的 Business(为了方便起见)的链接。)GET /Api/Employees/Z6W无论位于何处,都返回具有此 ID 的 Employee。
如果您想获取特定资源:将您的查询参数放在最后(而不是按照问题中描述的层次结构顺序)。您可以使用 URL 查询字符串 ( GET /Api/Employees?City=X7N) 或矩阵参数表达式 ( GET /Api/Employees;City=X7N;Business=A4X,A5Y)。这将使您能够轻松地表达特定城市中所有员工的集合 - 独立于他们所在的业务。
侧节点:
根据我的经验,初始的分层域数据模型很少能满足项目期间出现的额外要求。在您的情况下:考虑位于两个城市的企业。您可以通过将其建模为两个独立的业务来创建解决方法,但是如果员工一半时间在一个地方工作,另一半时间在另一个地点工作呢?甚至更糟:他只清楚他在哪个城市工作,但没有明确定义?
| 归档时间: |
|
| 查看次数: |
7575 次 |
| 最近记录: |