我最近负责一个小项目,即从内部数据库到第三方产品设置定期(每日和每周之间)数据转储。这个项目与我公司的愿望(我分享的一个)很好地吻合,开始在我们的数据顶部建立一个正式的服务层/ API。
我个人的偏好是那些API应该采用RESTful端点的形式 - 但是,现在我认为这是一个很大的设计问题 - 让我解释一下......
看看有问题的数据,它并不复杂。如果我要构建一次性查询,它在概念上看起来有点像:
select o.order_num, o.order_date, p.product_description, sr.sales_rep_name
from order o, line_item li, product p, sales_rep sr
where li.order_num = o.order_num
and li.product_id = p.product_id
and sr.sales_rep_id = o.sales_rep_id
and o.order_date >= [some arbitrary date]
将我的大脑翻转到资源模式",我可以考虑如何将这个基本数据模型转换为URI /有效负载而不会有太多麻烦:
GET /orders/123
{
"order_num": 59324,
"order_date": "2014-07-07",
"sales_rep_uri": "/salesRep/34",
"line_items_uri": "/order/123/lineItems"
}
获取有关销售代表的更多信息:
GET /salesRep/34
{
"sales_rep_name": "Jane Doe",
"open_orders_uri": "/salesRep/34/orders"
}
获取有关订单项的更多信息:
GET /orders/123/lineItems
{
"line_items": [
{"order_uri": "/order/123", "product_uri": "/products/68"},
{"order_uri": "/order/123", "product_uri": "/products/99"}
]
}
等等。我并不说它是一个完美的API,我只是试图证明它并不完全是考虑你如何表达数据的火箭科学通过RESTful URI以一种很好的规范化,面向资源的方式建模。但这正是设计问题发挥作用的地方......
一方面,我可以发出一个查询来很容易地解决问题,但是查询的本质要求各种域概念紧密耦合(换句话说,利用连接将所有规范化数据组合在一起)进入一个不错的,定制的非规范化结构)。
另一方面,经历思考RESTful API的心理过程会让我回到那条保持良好分隔的道路上 - 例如要求"订单123"不应该把这个巨大的图表发回给我,在那里我可以看到完整的产品描述,销售代表的电话号码等等。一个完整的HATEOAS级RESTful API的概念决定了消费者应该做的随后的GET只能根据需要深入了解这类细节。
我的问题归结为:解决这个用例似乎很容易用直接查询做,而且很难对付一个好的&整洁的RESTful API(我想象一下1000个单独的GET,它需要我组装一周的数据,而不是查询运行所需的几秒钟)。是不是有一些优雅的RESTful设计的优雅微妙,我不明白这会阻止我看到一个好的解决方案,或者我试图将一个圆形钉子放入一个方孔(即REST不擅长拉大数据)跨多个资源批处理?)
答案 0 :(得分:0)
我只是将其作为一种潜在的解决方案抛弃:
从概念上讲,我将此查询的结果视为自身的资源 - 例如“orderReport”。
将此作为自己的资源处理,API的行为类似于:
GET /orderReport/[some arbitrary date]
然后,您可以使用201 Created
等位置标头发回Location: /orderReport/[GUID]
(如果查询运行相对较快)。或者,如果查询需要一段时间才能运行(老实说,我不知道它是否有效),您可以发回一个202 Accepted
,其地址标题为Location: /orderReport/[GUID]/status
然后,您可以针对这些网址跟进GET,以获取报告状态(200 OK
,如果仍然处理没有错误,201 Created
,其中位置标题指向报告网址,如果已完成)或者报告本身。
除了满足用例要求所严格需要的数据之外,没有什么可说的报告数据也不能包含HATEOAS,例如:
{
[
{
"order_num": 123,
"order_uri": "/orders/123",
"order_date": 2014-07-03,
"product_description": "widget",
"sales_rep_name": "Jane Doe",
"sales_rep_uri": "/salesRep/34"
},
{
"order_num": 456,
"order_uri": "/orders/456",
"order_date": 2014-07-04,
"product_description": "gadget",
"sales_rep_name": "Frank Smith",
"sales_rep_uri": "/salesRep/53"
}
]
}