我读过有冲突的"意见"是否应该在JSON请求中删除信封或回复。
示例:
{
"data": {
"foo" : "bar",
"baz" : "Xyzzy"
}
}
应该(假设)写成:
{
"foo" : "bar",
"baz" : "Xyzzy"
}
但是,为了与SOLID原则保持一致,此结构应该是可以扩展的,但是关闭以进行修改。因此,删除信封将是一个坏主意。正确?
如果稍后我决定需要向入站JSON信息添加更多信息,那么执行此操作会更加清晰:
{
"data": {
"foo" : "bar",
"baz" : "Xyzzy"
},
"extended-data": {
"abc" : 123
}
}
比这样做:
{
"foo" : "bar",
"baz" : "Xyzzy",
"abc" : 1234
}
前者允许先前编写的代码,用于查找"数据"节点执行没有失败或更改。后者要求重写代码以寻找新值。
目前的最佳做法是什么,请找到您的来源:我需要接受的标准而不是意见。
更新
要回答异议:"如果添加字段,则必须更改代码。"
不是真的。我不必更改代码来处理新字段,我只需要为新数据添加新的处理程序:
示例:
function delegateTask($json) {
$this->doSomething($json->data);
}
扩展后:
function delegateTask($json) {
$this->doSomething($json->data);
$this->doSomethingElse($json->extended);
}
如果我只使用HTTP作为信封,我必须重写doSomething()。如果我以SOLID方式执行,我只需要添加一个查看新数据的函数。
不重复: 这个问题不是When in my REST API should I use an envelope? If I use it in one place, should I always use it?的重复,因为这个问题具体涉及S.O.L.I.D原则以及与信封相关的代码扩展。不只是将错误消息返回给客户端。
答案 0 :(得分:1)
信封是名称空间。命名空间是模块化设计和关注点分离的好工具。
考虑用于使用JSON API的事物类型。网格等将实际数据与分页和其他元数据分开,不那么脆弱。
我认为你可以在SOLID中应用“我”。
接口隔离原则 - “许多客户端特定接口优于一个通用接口。
使用信封,我可以采用任何API架构并将其与我选择的任何Javascript组件相结合,而无需担心冲突或必须重命名字段以使事情发挥作用。
这同样适用于API聚合。我可以在一次调用中组合2个单独的结果,以提供对特定用途最有效的“视图模型”。更容易与信封聚合。
关注像OData这样的标准,这个标准背后有许多聪明人。
就扩展和生命周期而言,我只是发布一个v2 API并维护旧的API,直到它被弃用。 API的多版本是常见做法(例如:eBay,Salesforce)。
答案 1 :(得分:1)
据我所知,这实际上是关于消息处理,而不是特定于JSON,REST等。
前者允许以前编写的代码,它寻找“数据”节点执行而不会出现故障或更改。后者要求重写代码以寻找新值。
目前最佳做法是什么,请找到您的来源:我需要接受的标准而不是意见。
我所知道的最好的参考是Versioning in an Event Sourced System,Greg Young。
简而言之
还有schema evolution上的Oracle参考,其中描述了“您可以安全地对您的架构执行的修改,而不会有任何顾虑。”它引用了这些相同的规则。
Avro的详细信息schema migration rules描述了生产者架构和消费者架构的解析方式。相同的基本想法,更多关于更改数据类型的细节。
RFC 4287描述了Atom Syndication中的“必须忽略外部标记”要求。 Versioning XML Vocabularies包括对必须忽略的良好讨论。
请注意,我们真正谈论的是处理模型,David Megginson points out。兼容性保证是采用正确的处理模型的结果。
你是否应该删除信封
信封对我来说似乎是浪费时间。添加值为state的字段与添加保存记录的新字段之间没有任何有用的区别。
message.get('foo').orElse('baz')
message.get('data').get('foo').orElse('baz')
抱歉,我无法区分。看起来像自行车脱落。
但如果用具有语义意义的记录替换泛型包络,并使用一个理解它可能无法理解消息的所有部分的处理模型,那么它非常强大(无论是否使用顶级字段或记录)。
另外,请注意,如果您处于管道中间,“必须忽略”表示忽略,而不是扔掉 - 您需要将整个消息传递到下一个阶段管道,并允许它自己决定应用哪些处理规则。
所以,我对你的评论的看法是:如果信封具有语义意义,那就没问题。你能举个例子吗?
因此,从我的角度来看,没有充分理由选择以下任何一种
get[xyzzy]
get[data][xyzzy]
get[data/xyzzy]
因为“数据”在任何一种拼写中都不会告诉处理引擎任何有用的东西。
另一方面,将消息分解为消费者可能关心的独立逻辑部分是有趣的。考虑事件HTTPRequestReceived - 这样的消息可能是什么样的?显然,我们关注事件本身(以便观察者可以评估他们对消息的兴趣),以及关于记录内容的数据,数据,可能是对人类或机器人流量的评估,来源事件......
{ event : { type : HttpRequestReceived }
, source : { logFile : ..., position : ... }
, rawData : [ ... ]
, botAnalysis : { ... }
}
我可以轻松地使用URI作为命名空间。
你可以。性感变体是将标识符用作键,用于查找模式定义
{ http://example.org/event :
{ http://example.org/event/type : HttpRequestReceived }
....
Schema.org有一个用于重复使用的常用概念词汇
{ http://schema.org/dateCreated : 2017-02-13 }