Web services 定义RESTAPI

Web services 定义RESTAPI,web-services,rest,api-design,Web Services,Rest,Api Design,我想知道定义RESTAPI的最正确或最佳实践方法是什么。假设我有一个处理汽车及其零部件的应用程序。任何api都将首先从顶级汽车开始。因此,在定义api时,我应该使用: [url]/{resourceName}/{carId}/{resouorceId} 作为一个例子,假设我想要一个引擎,所以: [url]/engine/123/456 其中123是汽车id,456是发动机id。或者,将资源放在顶级容器(在本例中为汽车)之后是更好的做法,例如: [url]/{carId}/{resourceN

我想知道定义RESTAPI的最正确或最佳实践方法是什么。假设我有一个处理汽车及其零部件的应用程序。任何api都将首先从顶级汽车开始。因此,在定义api时,我应该使用:

[url]/{resourceName}/{carId}/{resouorceId}
作为一个例子,假设我想要一个引擎,所以:

[url]/engine/123/456
其中123是汽车id,456是发动机id。或者,将资源放在顶级容器(在本例中为汽车)之后是更好的做法,例如:

[url]/{carId}/{resourceName}/{resourceId}
{
    "from_account_id": 123,
    "to_account_id": 456,
    "amount": "100.00"
}
因此,同样的例子是:

[url]/123/engine/456
或者这有关系吗?是否存在“行业最佳实践”类型的方法?据我所知,我读到的大部分内容都有“使api直观易懂”的意思

此外,api是否或是否应该具有完全的表达能力,例如,所有api(无论采用何种方法)是否都应该类似于以下内容,即使api始终适用于此特定应用的汽车

[url]/car/{carId}/{resourceName}/{resourceId}
例如:

[url]/car/123/engine/456
[url]/car/123/wheel/1

我知道这可能会被解释为一篇只会引起争论的帖子,但我真的在寻找帮助,以追踪哪些内容可能最为广泛接受。

REST与uri或HTTP毫无关系。这不是一个标准;这是一种建筑风格或范例。在罗伊·菲尔丁(Roy Fielding)的论文中,他确定了建筑风格“宁静”的某些标准。HTTP恰好满足这些标准,这使得它成为实现RESTful体系结构的好协议。但是REST本身与HTTP无关

在REST中,URI是不透明的,这意味着它们除了唯一地标识资源之外,不传递任何其他语义。例如,像
/dfjSuX7kx
这样的URI是完全有效的。当然,这并不意味着我们必须像那样使用URI;最好使用你能理解的东西

你想知道你是否应该去:

[url]/{resourceName}/{carId}/{resourceId}
我想说的是,最好是:

[url]/{resourceName}/{resourceId}
然后将
carId
作为表示的一部分。为什么呢?我们知道其中一个要求是您的URI必须唯一地标识资源。现在我们有一个engine
456
,它是car
123
的一部分,这意味着您正在用URI
/engine/123/456
标识特定的资源。但假设汽车
123
总计,发动机移至汽车
789
。现在,同一资源的URI是
/engine/789/456
。请记住,发动机的
456
没有任何变化;它仍然是相同的引擎。唯一的问题是,它现在是连接到一个不同的汽车。但这并不意味着唯一标识它的URI也必须更改(因为这样它就不再唯一标识它)。唯一标识发动机的是它的id,而不是它所连接的汽车。因此,最好只使用
/engine/456
并返回如下表示:

{
    "id": 456,
    "carId": 123,
    "cylinders": 6,
    "hp": 350,
    ...
}
您还询问是否可以这样做:

[url]/{carId}/{resourceName}/{resourceId}
我完全不建议这样做。假设您已在
http://my.car-api.com
http://my.car-api.com/123
实际上是什么意思?当然,它是RESTful的,因为URI是不透明的,但是在查看URI时很难理解它的含义,因此最好使用
/car/{carId}

对于最后一个问题,您询问以下内容是否可以接受:

[url]/car/{carId}/{resourceName}/{resourceId}
子资源还可以,我见过人们使用它,我也在我创建的一些RESTAPI中使用过它。但就我个人而言,我正朝着为每个资源提供顶级URI的方向前进。这是因为我们已经可以通过从URI返回的表示来传递层次关系或“所有权”的概念,而不是将其编码到URI本身(请记住,URI除了唯一标识资源之外没有其他意义)。我还注意到,在实现控制器、错误处理程序和转换器(将DTO转换为域对象的助手类,反之亦然)的方式中存在正交性问题;支持嵌套URI结构使我很难编写通用代码(尽管其中一些原因是由于我使用的框架Spring的工作方式)

你可以决定你想要多“安静”;我见过的量化API的RESTfull的最佳度量是。我建议你选择一个你满意的水平。没有必要完全教条主义,完全平静;这取决于你的情况。但我发现进入第3级(HATEOAS)给我带来了很多好处,因为我的自定义媒体类型(即,我使用
application/vnd.my.api.resource.v1+json
,而不仅仅是
application/json
)都有很好的文档记录,并且能够很好地传达它们的语义。我的客户也不必构造URI,因为他们只需遵循链接即可。这些表示也是自文档化的,因为您可以按照相关文档的链接来获取有关处理资源的说明

我唯一强烈建议的是选择一种风格并坚持下去。我不喜欢混合范例;因此,如果您的目标是使用RESTful,那么不要让任何RPC内容潜入您的API中。这可能有点困难,因为REST是基于名词的,RPC是基于动词的(即行为),有些概念很容易映射到RPC。例如,如果您有一个银行API,您希望提供从一个帐户向另一个帐户转账的功能。真正是RPC ish的“REST”实现可能会将类似于
/account/{accountId}/transfer?的URI公开给={toAccountId}&amount={amount}
(它直接映射到
帐户
对象上的方法调用:
帐户.transfer(amount,toAccountId)
;因此是RPC)。RESTful的方式是在
/transaction
中公开
事务
资源,您可以在那里
{
    "id": 789,
    "source_account_id": 123,
    "destination_account_id": 456,
    "amount": "100.00",
    "_links": {
        "self": { "href": "/transaction/789" }
    }
}