编写该代码,就像它会伴随着一个知道您的住所的暴力精神变态者一样。
大家好!
我是在线酒店预订服务Ostrovok.ru中集成开发团队的团队负责人,今天我想与大家分享各种API的经验。

作为与外部供应商合作的系统的开发人员,我经常遇到各种API-最常见的是SOAP / REST或类似的东西。 然而,与其中许多人一起工作给人留下的印象是,它们是不受技术规则或常识指导的,就像是格里高利·奥斯特(Grigory Oster)的“ Bad Advice”一书一样。 在本文中,我将尝试以“坏建议”的方式描述此类情况,并考虑与XML相关的示例。 欢迎发表评论和讨论。
历史背景
SOAP (英文)。简单对象访问协议-用于访问对象的简单协议)-一种用于在分布式计算环境中交换结构化消息的协议。 SOAP最初主要用于实现远程过程调用(RPC)。 现在,该协议用于交换XML格式的任意消息,而不仅仅是用于调用过程。
转到示例
1.将xml传递给url
API用户最想要的是什么? 当然,简单,可靠和简洁。 因此,我们不要阅读请求正文,而是将XML作为URL编码的信息作为请求路径的参数来接受! 有什么更好的方法:
http://exapmple.com/xml/form.jsp?RequestName%3DHotelRequest2%26XML%3D%3C%3Fxml%2Bversion%3D%221.0%22%2Bencoding%3D%22UTF-8%22%3F%3E%0A%3CHotelRequest2%2BBuyerId%3D%22test%22%2BUserId%3D%22test%22%2BPassword%3D%22test%22%2BLanguage%3D%22en%22%2BHotel%3D%22-100%22%2BProductCode%3D%221--%22%2BArrivalDate%3D%2223.12.2018%22%2BDepartureDate%3D%2224.12.2018%22%2BArrivalTime%3D%22%22%2BDepartureTime%3D%22%22%2BCurrency%3D%222%22%2BWhereToPay%3D%223%22%2BNumberOfGuests%3D%220%22%2BNumberOfExtraBedsAdult%3D%220%22%2BNumberOfExtraBedsChild%3D%220%22%2BNumberOfExtraBedsInfant%3D%220%22%2B%2F%3E
一切都变得很简单,并且不需要从查询中减去某些主体-您永远不会知道它可能有什么问题。
扰流板我不知道为什么要这么做。 这里的问题如下:许多服务器对可通过它们的请求路径的长度有限制。 如果XML的数据量很大,则可能会导致413 Entity Too Large错误,这是其中一种情况。 另外,由于我们在发送之前进行了url编码,因此信息量正在增加。
2.通过过度嵌套数据对象进行信息传递
让我们考虑一下如何使答案中的信息尽可能困难? 让我们使用嵌套结构,甚至使用不同的格式! 言归正传-
<Request> <InnerRequest> <RQ>[{"someInfo":"base64Data"}] </RQ> </InnerRequest> </Request>
确实,顶级xml,在它里面是另一个xml,在它里面是json,其中数据以base64表示,再次以json形式出现,它已经包含了我们需要的信息! 一个很好的解决方案,几乎就像童话故事一样,隐藏在一个鸡蛋中,关于科什切伊的死。
扰流板最明显的缺点之一是解析响应的速度变慢,直到遍历所有嵌套结构为止,此后可能会发现错误代码以json形式连接,而不是更高级别。 我知道在xml / json内的base64中编码二进制数据是一种常见的做法,但是在不同格式内编码不同格式已经不是好事了。
3.添加与请求数据无关并且在数据格式内无效的信息
假设XML出现在请求主体中,我们对其进行处理并给出答案。 对于设计良好且负载沉重的系统而言,它看起来太复杂了。 让我们强制用户在请求正文中发送数据类型。 怎么做? 当然,在请求正文中。
XML= <Request> ... </Request>
以这种简单的方式,我们将永远知道我们收到了XML格式的请求。
扰流板事实证明,我们必须在已经形成的请求主体中添加更多的前导字节,只有在此之后才可以发出请求。 如果您不需要根据请求数据的类型更改前导字节,则很幸运。 在这种情况下,最好使用http Header指示数据类型,而不更改请求正文。
4.无需重复数据
假设我们在XML响应的结构中具有非常非常重要的信息。 如何向用户展示? 最明显的是-让我们多次展示它作为答案的一部分,然后他肯定会注意它。
<Response> <Obj Info="Important"> <ObjSetting Info="Important"/> <Name>SomeName</Name> <Info>Important</Info> </Obj> </Response>
之后,最终用户一定会注意“信息”字段。
扰流板在这种情况下,我考虑了一下,甚至询问提供API的公司有关Info字段的含义以及不同级别的标签中的信息是否会有所不同。 答案是:不,不会-他们彼此重复。 如果没有必要,为什么要误导用户并使答案更加困难?
5.分别传递相同类型的参数,而不是数组
在我们用来搜索酒店的API之一中,有一些字段指示客人的年龄。 哪种表示形式最适合用来传达此信息? 格式如下:每个年龄段将是一个单独的强制性XML标记,并且我们将值0视为缺少此参数。
<Request> <Age1>20</Age> <Age2>20</Age> <Age3>0</Age> <Age4>0</Age> </Request>
扰流板这一次有几个问题:不可扩展性,冗余信息,此外,如果客人是新生婴儿,年龄实际上可以为零。 在这种情况下,您需要使用数组而不是唯一命名的标签。
6.转发来自先前请求的信息,作为API调用链的一部分
现在是时候考虑我们API的安全性了。 我们如何理解用户从我们之前的答案中收到信息? 当然,让他给我们发送答复!
<Request> <RequestInfo/> <PreviosResp> ... </PreviosResp> </Request>
扰流板要继续使用API,必须发送API之前步骤中外部系统的整个响应,而不是来自其中的一些重要数据,甚至是肯定与该答案相对应的哈希。 数据量过大。
7.请勿使用发生错误的标记,例如错误标记或http代码
我们制作了漂亮的API,并将其介绍给全世界。 但是一旦出现问题,由于内部错误,我们将无法对用户做出响应。 在这种情况下该怎么办? 只需给出一个响应模板,没有数据,没有错误代码或任何其他信息。 没有人应该知道我们理想的API有时可能无法正常工作!
这样的答案的一个例子:
<Response> <ImportantInfo/> </Response>
-响应码为200 OK。
扰流板掩盖犯下的错误是非常糟糕的做法。 问题在于,答案似乎一切都没有问题:没有<Error>
标记,http状态表明一切正常。 在这种情况下,有必要对接收到的信息进行额外的验证,以便在我们的系统中不存在无法预料的后果。
结论
尽管有大量有关使用SOAP / XML技术和API设计的文档,但是仍然存在许多问题,并且某些解决方案与常识背道而驰。 我希望通过这篇文章,我能够吸引开发人员注意那些不是最成功的方法,以便将来减少他们的数量。