您的直觉是正确的。这不是合适的REST。有时可以接受,但大多数情况下,这表明您的领域需要重新设计。
很多时候,有一个领域模型等待被发现。通常,“send_signal”之类的东西告诉您,您已经将API建模得太接近某个库、后端服务或数据库了。毕竟,API是您提供的接口。
正如我之前写过的那样:REST中的R代表资源(这并不正确...等)。
考虑资源。不要考虑过程或调用,也不要考虑内部工具、后端服务或系统架构。那是您自己的东西。API用户只应该关心对API用户有意义的(干净的)抽象。
“/call”和“/.../send_signal”都过于关注过程和内部细节。
你想对设备做什么?你想打开它的相机吗?这将是对 ID 为 1337 的设备上的
Camera
模型进行更新:
PUT /device/1337/camera { power: "on" }
你想要一个设备来压缩一些日志文件并将它们发送到调试服务器?你正在创建一个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,它们非常难以使用,而且维护起来更加困难。本文的教训是:第一个暴露了服务器领域模型,只包含对API用户有用的少量属性。第二个则过于紧密地围绕着各种内部工具和系统进行建模。此外,这完全忽略了更重要的REST部分:发现。链接、头信息、重定向等等。但你明确问到了如何命名资源,所以我的答案也是关于这方面的。一旦你有了资源和领域模型的架构,回到白板前重新做一遍:现在包括链接、头信息或其他元数据,以便你的API客户端可以发现他们能做什么以及在哪里可以做到。”