REST – 复杂的应用程序
我正在努力将RESTful原则应用于正在处理的新Web应用程序。 尤其是,RESTful的思想是,每个HTTP请求都应该携带足够的信息,以便接收者处理它,使其与HTTP的无状态特性完全一致。
该应用程序允许用户search药物。 search接受filter作为input,例如,退回停药,包括免费治疗等..等等。 总共有大约30个可以应用的filter。
此外,可以input患者详细信息,包括患者的年龄,性别,当前的药物等。
如果所有这些信息都包含在每一个请求中,那么要安定下来? 这似乎给networking带来了巨大的开销。 另外,URL长度的限制,至less对GET来说,是不可行的?
“作为资源过滤”是一个完美的机智。
您可以将filter定义放入filter资源,并可以返回filterID。
PUT是幂等的,所以即使filter已经在那里,你只需要检测你以前看filter,所以你可以返回正确的filterID。
然后,您可以为其他请求添加一个filter参数,并且可以获取用于查询的filter。
GET /药物?filter = 1234&page = 4&pageize = 20
我会通过某种规范化过程运行原始filter,只是为了有一个规范化的集合,所以,例如filter“firstname = Bob lastname = Eubanks”与“lastname = Eubanks firstname = Bob”是相同的。 那只是我而已。
唯一真正的问题是,随着时间的推移,你可能需要淘汰一些filter。 如果有人用缺less或过时的filter发出请求,您可以简单地将请求错误。
编辑回答问题…
我们从基本面开始吧。
简单地说,你想指定一个filter用于查询,但这些filter(可能)涉及和复杂。 如果是简单/药物/ 1234,这不会是一个问题。
实际上,您总是需要将filter发送到查询。 问题是如何表示该filter。
像REST系统中的会话这样的基本问题是,它们通常是“带外”pipe理的。 当你说,去创build一个药物,你把药物或药物资源,你可以得到一个参考回来的药物。
通过一个会话,你可以(通常)取回一个cookie,或者其他一些令牌来表示该会话。 如果你的药物资源也创build了一个会话,那么实际上,你的请求创build了两个资源:一个药物和一个会话。
不幸的是,当你使用类似cookie的东西,并且你的请求需要这个cookie时,资源名称不再是资源的真实表示。 现在它是资源名称(URL)和cookie。
因此,如果我在名为/ medications / search的资源上执行GET操作,并且Cookie代表一个会话,并且该会话恰好有一个filter,那么可以看到这个资源名称/ medications / search是如何生效的,根本没用。 由于Cookie和会话及其中的filter的副作用,我没有所有需要的信息来有效地使用。
现在,您可以重写名称:/ medications / search?session = ABC123,将cookieembedded到资源名称中。
但是,现在你要进入典型的会议合同,特别是他们是短命的。 所以,这个命名的资源是不太有用的,长期的,而不是无用的,只是不太有用。 现在,这个查询给了我有趣的数据。 明天? 可能不会。 我会得到关于会议正在消失一些讨厌的错误。
另一个问题是会话通常不作为资源进行pipe理。 例如,他们通常是副作用,通过GET / PUT / DELETE显式pipe理。 会话也是Web应用程序状态的“垃圾堆”。 在这种情况下,我们只是希望会话正确地填充了这个请求所需的内容。 我们实际上并不知道。 再次,这是一个副作用。
现在,让我们把它的一点点。 我们使用/ medications / search?filter = ABC123。
显然,随便,这看起来是一样的。 我们只是将名称从“会话”更改为“filter”。 但是,正如所讨论的,在这种情况下,filter是“一stream的资源”。 他们需要被创build,pipe理等,就像药物,JPEG或系统中的任何其他资源一样。 这是关键的区别。
当然,你可以把“会议”当作一stream的资源,创造它们,直接把东西放入其中,等等。但是你可以看到,至less从清晰的angular度来看,“一stream”会议是不是真的这个案例是一个很好的抽象。 使用会议,就像去清洁工,交出你的整个钱包或公文包。 “是的,机票在那里,挖出你想要的东西,给我我的衣服”,特别是与filter明确的东西相比。
所以,你可以看到在30,000英尺的情况下,filter和会话之间的情况没有太大的区别。 但是当你放大时,它们是完全不同的。
有了filter资源,你可以select永远把它们变成持久的东西。 你可以过期,你可以做任何你想要的。 会话往往有预先设想的语义:短暂的生活,连接的持续时间等。filter可以有任何你想要的语义。 它们与会话中的完全分开。
如果我这样做,我将如何使用filter?
我会假设我真的不关心filter的内容。 具体来说,我怀疑我会查询“所有filter的名字search”。 在这个时候,这似乎是无趣的信息,所以我不会围绕它devise。
接下来,我会正常化filter,就像我上面提到的。 确保等效的filter真的是等效的。 你可以通过对expression式进行sorting,确保字段名都是大写的,或者其他的。
然后,我会将filter存储为XML或JSON文档,以适合应用程序的情况为准。 我会给每个filter一个唯一的键(自然),但我也会存储filter的实际文档的散列。
我会这样做,以便能够快速findfilter是否已经存储。 由于我正在规范化,我“知道”逻辑上等价的filter的XML(说)是相同的。 所以,当有人去PUT,或插入一个新的filter,我会做一个哈希检查,看看它之前是否存储过。 我可能会返回多个(哈希当然可以碰撞),所以我需要检查实际的XML有效载荷,看它们是否匹配。
如果filter匹配,则返回对现有filter的引用。 如果没有,我会创build一个新的并返回。
我也不会允许filter更新/ POST。 由于我分发了这些filter的引用,我会让它们不可变,所以引用可以保持有效。 如果我想要一个“angular色”filter,比如说“获取所有过期药物filter”,那么我会创build一个“名称filter”资源,将一个名称与一个filter实例相关联,这样实际的filter数据可以改变,但是名字保持不变。
也要注意,在创作过程中,你处于竞争状态(两个请求试图制作相同的filter),所以你必须考虑到这一点。 如果你的系统有很高的过滤量,这可能是一个潜在的瓶颈。
希望能够为你解决这个问题。
如果所有这些信息都包含在每一个请求中,那么要安定下来?
不可以。如果看起来你的服务器正在发送(或接收)太多的信息,那么很可能有一个或多个你尚未识别的资源。
devise一个RESTful系统的第一步也是最重要的一步是识别和命名你的资源。 你将如何做你的系统?
从你的描述来看,这里有一组可能的资源:
- 用户 – 系统用户(可能是医生或病人(?) – angular色可能需要在此处作为资源公开)
- 药物 – 瓶子里的东西,但它也可能代表瓶子的种类(数量和内容),或者它可能代表一个特定的瓶子 – 取决于你是药店还是只是一个服务台。
- 疾病 – 病人可能想服用药物的条件 。
- 病人 – 可能服用药物的人
- build议 – 一种可能有益于基于他们所患疾病的患者的药物 。
那么你可以寻找资源之间的关系;
- 用户拥有和属于许多angular色
- 药物已经和属于许多疾病
- 疾病有很多build议 。
- 病人有和属于许多药物和疾病 (贫穷的小伙子)
- 病人有很多build议
- build议有一个患者 ,有一个疾病
具体可能不适合你的特定问题,但这个想法很简单:在你的资源之间build立一个关系networking。
在这一点上,考虑URI结构可能会有帮助,但请记住, REST API必须是超文本驱动的 :
# view all Recommendations for the patient GET http://server.com/patients/{patient}/recommendations # view all Recommendations for a Medication GET http://servier.com/medications/{medication}/recommendations # add a new Recommendation for a Patient PUT http://server.com/patients/{patient}/recommendations
因为这是REST,所以您将花大部分时间来定义用于在客户端和服务器之间传输资源表示的媒体types 。
通过公开更多资源,可以减less每个请求期间需要传输的数据量。 还要注意URI中没有查询参数。 服务器可以是有状态的,因为它需要跟踪这一切,并且每个请求都可以完全独立。
REST是针对API的,而不是(典型的)应用程序。 不要试图将基本上有状态的交互变成无状态的模型,只是因为你在维基百科上阅读了它。
如果所有这些信息都包含在每一个请求中,那么要安定下来? 这似乎给networking带来了巨大的开销。 另外,URL长度的限制,至less对GET来说,是不可行的?
与服务器发送的资源大小相比,参数的大小通常是微不足道的。 如果您使用的这些大参数是networking负担,请将其放置在服务器上,然后将其用作资源。
URL长度没有重大限制 – 如果您的服务器有这样的限制,请升级它。 无论如何,这可能已经有几年了,充满了安全漏洞。
没有一切都不必在每一个请求。
每个资源(药物,患者病史等)都应该有一个唯一标识它的规范URI。 在某些应用程序(例如,基于Rails的应用程序)中,这将是“/ patients / 1234”或“/ drugs / 5678”之类的东西,但URL格式并不重要。
先前已经获得资源的URI(例如来自search或来自embedded在另一个资源中的链接)的客户端可以使用该URI来检索它。
您是否正在使用其他应用程序将用于search数据的RESTful API? 或者你正在build立一个terminal用户的Web应用程序,用户将login并执行这些search?
如果您的用户正在login,那么您已经具有状态,因为您将拥有某种types的会话Cookie来维护login状态。 我会继续创build一个包含所有searchfilter的会话对象。 如果用户没有设置任何filter,那么这个对象将是空的。
这里有一篇关于使用GET vs POST的好博客文章。 它提到了由Internet Explorer设置的2048个字符的URL长度限制,所以您希望对长请求使用POST。
http://carsonified.com/blog/dev/the-definitive-guide-to-get-vs-post/