我正在为设备管理系统设计REST API。
端点:
http://api.example.com/users
http://api.example.com/devices
我想要实现的是,有一个端点将在所选设备上执行某些操作。像这样:
http://api.example.com/devices/1/send_signal
我知道这与REST不兼容,我正在寻找建议以使其正确使用。
我正在考虑添加另一个端点,例如:
http://api.example.com/calls
因此,当用户向该端点发送带有deviceId参数的POST请求时,将在数据库中有一个新条目(具有所有调用的历史记录以及调用该函数的人员),并同时在指定设备上调用该函数。
这将是出色的体系结构并与REST兼容吗?
答案 0 :(得分:2)
http://api.example.com/devices/1/send_signal
我知道这与REST不兼容,我正在寻找建议以使其正确使用。
它与REST兼容。 REST不在乎您为资源标识符使用什么拼写。
这将是出色的体系结构并与REST兼容吗?
如果这是您想要的,请考虑如何通过网站获得相同的结果。客户将在浏览器中打开一个书签,也许会跟随一些链接,填写表格并提交。这一切都会起作用,因为(通用)浏览器了解HTML的处理规则,以及如何在HTTP中管理缓存元数据,等等。客户端在链中没有必要组成一个标识符-它要么使用服务器原样提供的标识符,要么使用HTML表单的通用处理规则来计算一个标识符。
OP显然使用动词来传达意图和过程,这不是RESTful的。
否;这是一个普遍的误解。 REST架构样式中没有任何关于标识符中人类可读语义的内容。 URL缩短器工作。
这类似于说程序中的变量名不应该是动词,因为它不能正确传达意图-编译器/解释器不在乎。
使用拼写约定不会使URI或多或少具有REST风格。参见Tilkov。甚至最好避免使用predictable identifiers,因为这样可以确保消费者读取超媒体表示形式中提供的标识符,即the point。
答案 1 :(得分:1)
您的直觉是正确的。这不是正确的REST。有时候可以,但是大多数情况下,这表明您的网域中的某些内容需要重新设计。
通常,有一个域模型等待发现。通常,诸如“ send_signal”之类的东西告诉您,您对API的建模过于接近某些库,后端服务或数据库。毕竟,API是您 提供的接口。
AS I've written before:REST中的R代表资源(这是不正确的。...等等)。
思考资源。不在过程或调用,内部工具,后端服务或系统体系结构中。那是你的东西。仅应对API用户有意义的(干净)抽象来烦扰API用户。
/call
和/.../send_signal
都对程序和内部结构感到非常烦恼。
您想对设备做什么?您想打开相机吗?这将是对Camera
上的Device
模型,ID为1337的更新:
PUT /device/1337/camera { power: "on" }
您想让设备bzip压缩一些日志文件并将其发送到调试服务器吗?您正在创建DebugSession模型:
POST /device/1337/debug_session { delivery_bucket: 42, compress: "bzip" }
您要设备将消息发送到某些服务器吗?在设备上创建Message
:
POST /device/1337/messages { to: john, body: "Hello World" }
以此类推。
那是REST。在REST中,您需要仔细建模领域模型。许多REST服务器确实很差劲,因为它们是某些关系数据库的非常薄的包装器,并且遭受太多的泄漏抽象。许多其他REST服务器确实很差劲,因为它们在后端服务,正在运行的作业或其他内部细节周围写得太近了。
如果我要启动新服务器,我想说:
POST /server/ { region: eu-1, size: xl, disk: 1MB }
不是:
POST /resources/blockdisks/create { size: 10GB } => 1337 is created
GET /resources/blockdisks/1337?include_attrs=mountpoint,format
GET /servers/available/map_for/eu-1?xl => DB-Zfaa-dd-12
POST /servers/reserve { id: DB-Zfaa-dd-12, attach: { id: 1337, mountpoint: /dev/sdb2, format: zfs }
(我没有做这个,我不得不处理这样的API,它们是要使用的PIAS,并且肯定可以维护更大的PIAS)
这里的课程:第一个课程展示了服务器的域模型,其中只有API用户感兴趣的属性很少。第二个模型的建模距离所有内部工具和系统都太近了。
编辑:并且所有这些都完全忽略了更重要的REST部分:发现。链接,标头,重定向等。但是您明确询问了有关资源的命名,这就是我的答案。一旦拥有资源,就可以对领域模型进行架构化,然后再回到白板上并一遍遍:现在包括链接,标头或其他元数据,以便您的API客户端可以发现他们可以做什么以及在哪里可以做。
答案 2 :(得分:0)
我认为您的做法正确。根据您对系统的评论,我可能会从这种方式开始,然后从那里开始。
POST http://api.example.com/devices/123/calls
这会将调用的详细信息发送到API,并将其保存到数据存储中,并将事件发送到适当的子系统或内部库以调出设备。
然后,您可以具有以下端点来获取呼叫详细信息。
GET http://api.example.com/devices/123/calls/456
GET http://api.example.com/devices/123/calls -This would also include query parameters to limit the results in some way, probably by date.
如果您想从所有设备上接听电话,则可以使用一些查询参数来限制结果集,也许是按日期。
GET http://api.example.com/devices/calls
请注意,如果这是仅由应用程序使用的内部API,则RPC样式可能是合适的。但是,通过遵循HTTP / REST,您将使您的软件更具延展性,因此您可以通过更多方式使用它,而无需使其特定于任何一种功能。
如果您想了解更多信息,这是一篇有关REST vs RPC的好文章。 https://cloud.google.com/blog/products/application-development/rest-vs-rpc-what-problems-are-you-trying-to-solve-with-your-apis