以RESTful方式重新排序商品

时间:2019-02-14 03:26:25

标签: rest

我有一个包含以下数据的表:

AdminsMacBook-2:dockertest2 newadmin$ more src/main/docker/app.yml
version: '2'
services:
    dockertest2-app:
        image: dockertest2
        environment:
            - _JAVA_OPTIONS=-Xmx512m -Xms256m
            - SPRING_PROFILES_ACTIVE=prod,swagger
            - SPRING_DATASOURCE_URL=jdbc:mysql://dockertest2-mysql:3306/dockertest2?useUnicode=true&characterEncoding=utf8&useSSL=false
            - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
        ports:
            - 8080:8080
    dockertest2-mysql:
        extends:
            file: mysql.yml
            service: dockertest2-mysql

这是一个列表,用户可以重新排列(因此在位置列中)。我的问题是,我怎样才能轻松地做到这一点。例如,如果我想将Fred移到位置2,该如何发送请求?

目前,我有这样的事情:

AdminsMacBook-2:dockertest2 newadmin$ more src/main/docker/Dockerfile 
FROM openjdk:8-jre-alpine

ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
    JHIPSTER_SLEEP=0 \
    JAVA_OPTS=""

# Add a jhipster user to run our application so that it doesn't need to run as root
RUN adduser -D -s /bin/sh jhipster
WORKDIR /home/jhipster

ADD entrypoint.sh entrypoint.sh
RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh
USER jhipster

ENTRYPOINT ["./entrypoint.sh"]

EXPOSE 8080

ADD *.war app.war

这会将当前处于位置4的用户1(Fred)移至位置2。SQL代码还将运行查询,该查询将更改其他用户的位置以适应Fred的新位置。

执行此操作的正确的RESTful方法是什么?

4 个答案:

答案 0 :(得分:1)

为了有效地执行此操作,请使用哈希表,并且从不对所有内容进行重新排序,只需通过更改其索引键将它们置于两者之间。我是什么意思?

让我们说

1 a
2 b
3 c
4 d
5 e

PUT /user/1/reorder/2

在我里面,位置也是从索引中的位置得出的

1  2   b
2  2.5 a
3  3   c
4  4   d
5  5 e

正如Kajow所指出的,这种方法有两个问题:

  • 多次重新订购后,浮点数可能不足

  • 浮点数精度

要解决它们:

  • 我们不使用浮点数,而是使用大数100000、200000、300000等,然后重新排序200000、250000、30000等。

  • 在x次重新订购后,我们重置为100000,200000,300000,400000。可能有一种方法可以使每个x分区仅对小零件重新排序,以保持此过程简单,小​​巧和零星

答案 1 :(得分:0)

  

执行此操作的正确的RESTful方法是什么?

想法是您的API是您的域模型所伪装的,因此它可以假装成无聊的Web文档存储。

在可能的情况下,您希望修改的URI与GET的URI匹配,因为这样您就可以使用通用组件来管理客户端的缓存失效。

因此,如果您通过类似这样的请求读取用户列表

GET /flintstones

然后,您要使用以下一个或多个想法来修改表示形式

POST  /flintstones
PUT   /flintstones
PATCH /flintstones

对于PUT请求,正文中的表示可能只是重新排序的列表:

Pebbles
Fred
Wilma
Betty
Barney

然后由您的实现决定如何获取该文档并将其表示为一系列SQL调用。

  

但是,难道您最终带宽效率降低,数据库查询效率降低吗?

对于大文件的少量编辑,PUT可能不是您的最佳选择。相反,您可以获取与URL相同的信息,将其嵌入到补丁文档中,然后使用PATCHPOST

所以它可能是一个Web表单-我们将使用application/x-www-form-urlencode数据将表单条目传递回服务器,以便它可以确定要做什么。或者(对于交换JSON表示的情况,我们可以写出一个JSON Patch文档来描述更改)。

答案 2 :(得分:0)

我喜欢@zardilior的方法,但略有不同。我想用ID来指代 related 实体以及应该是什么... relationship 的概念,以便您可以做类似

PUT /user/1/after/2

...或...

PUT /user/1/before/3

为了加强这一点,我不会在GET /users上将职位发送给客户。相反,我只是将它们以正确的顺序返回给客户端,而没有position值。这使客户不必重新查询就可以得到更正的职位...甚至不必知道职位的数据类型(如果使用@zardilior提出的职位拆分方案,这可能会很糟。)我在对整个集合重新排序还是使用头寸拆分方面发生了冲突。如果您仍然使用现有的int数据类型,则可能唯一可以做的就是对整个集合重新排序。

答案 3 :(得分:0)

在REST体系结构设计中,您主要专注于将客户端与相应的API分离,以允许服务器端自由发展而不会破坏客户端。如果许多不受您控制的客户端请求您的API,则此类属性特别方便。尽管仅使前端或移动UI与支持API对话的简单自定义解决方案实际上并不需要这种架构,但是如果您仍然坚持要实现这种架构,没有人会阻止您。但是这里的事实是,如果您不严格遵守严格的约束条件,那么您就不会从REST架构中受益。这也包括任何客户。如果只有一个客户不遵守这些准则,则可能会出现互操作性问题。

REST的核心是对Web上使用的交互模型的概括,这使其可以扩展到今天的大小。交互模型的主要前提应该是服务器/ API正在教客户如何下一步做什么以及如何实现。如果查看大多数Web交互,您将看到服务器正在提供用户可以与之交互的链接和表单。在单击链接时,客户端将加载该链接的内容并将其呈现给客户端。表单允许客户端提供服务器代表客户端执行某些任务所需的信息。这样,客户不需要任何带外信息,例如相应的文档或手册。通过the affordance of certain elements,应该很清楚有人必须如何与这种元素进行交互。即如果可视化数据表,您可以在其中编辑或删除某些项目,则该表通常包含垃圾桶或铅笔的图像。在单击铅笔后,将呈现一个包含可用数据的表单,该数据可用于更改该条目的某些元素,而在单击垃圾桶图标时,表格条目将被删除(可能经过安全检查之后)。整个交互流程可以概括为HATEOAS-超文本作为应用程序状态的引擎。

有关如何使用REST实现某些功能的基本建议是对手头任务进行建模,就好像您要与Web页面进行交互一样。因此,如何通过REST实现类似排序的功能?服务器要么已经向客户端提供了信息,要么允许修改(集合)资源以满足要求。通过链接可以简单地提供第一种方法,可以通过图标进一步访问这些链接,这些图标说明了交互可能性的目的。在表中,这可以指示您可以按特定的列名或类似名称进行排序。另一种可能性是服务器正在教客户端如何执行下一步操作。在这里,服务器可以允许通过将条目拖动或单击到新位置来在本地重新排列条目,然后将所需结果发送到服务器,或者允许客户端将某个脚本上载到执行该操作的服务器上。

由于REST是针对应用程序而非人类的,因此某些图标的功能可能无法直接由应用程序使用。通过使用绝对URI基于standardized的链接关系名称(应为extensions或使用诸如dublin-core或其他microformats之类的常见本体,而不是图标,通过链接关系名称来告知承受能力。某些媒体类型可能还会提示客户可能期望的链接关系以及在哪种上下文中使用这些链接关系。

回到有关如何在REST体系结构中对项目重新排序的实际问题。根据集合的大小,可以使用多种方法。与Web类似,在Web中,一个小表可能会提供一个编辑控制元素来立即更新整个表,在REST体系结构中也可以做到这一点。在此,可以提供带有链接关系edit的链接,以通知客户端,如果它要编辑整个集合,则应访问链接关系名称随附的URI。在遵循该URI时,它可能会获得表示与HTML表单类似的表单的媒体类型,该媒体类型允许使用HTTP PUT请求立即将该集合的更新表示发送到集合资源。

如果该集合中有很多条目,或者条目的页面可能很多,则采用另一种方法可能更有利。一种可能是客户端收集所有(或足够)可用条目或页面,并计算对该资源进行的更改,以将当前订购转换为所需订购。这是HTTP PATCH操作的完美匹配。通过application/json-patch+json,您可以同时move数十个条目。由于必须以原子方式应用请求,因此,所有更改要么全部应用,要么不应用。

尽管您也可以通过HTTP POST请求发送应由服务器执行的脚本,因为此处脚本是根据服务器自身的语义执行的,所以除了危险之外,这不是危险的。作为服务器的REST理念的精神,不是在指导客户下一步该做什么,而客户必须对服务器的内部结构有一定的了解。

由于Clayzardilior的答案都提出了某种URI结构来移动某些条目,因此我强烈反对这种说法。首先,URI整体上是指向资源的指针。如果您通过GET请求条目,则它实际上是一个缓存键,并且对该URI的任何非安全请求都将删除缓存的值。田野造了caching a requirement in a REST architecture,而不是一个选择。客户进一步不应解释URI,因为它们不传达含义。这就是链接关系的用途。正如Fieldings论文chapter 6.2中提到的那样,URI是唯一的,应该尽可能少地更改。

  

... REST中的资源定义基于一个简单的前提:标识符应尽可能少地更改。由于Web使用的是嵌入式标识符,而不是链接服务器,因此作者需要一个标识符,这些标识符与超媒体引用所要使用的语义紧密匹配。即使访问该引用的结果可能随时间变化,该引用也可以保持不变。 REST通过将资源定义为作者打算识别的语义而不是创建引用时与这些语义相对应的值来实现此目的。然后留给作者以确保为参考选择的标识符确实标识了预期的语义。 ...

     

...资源可以具有许多标识符。换句话说,当用于访问服务器时,可能存在两个或两个以上具有相同语义的不同URI。也可能有两个URI,导致在访问服务器时使用相同的机制,但是这些URI标识两个不同的资源,因为它们并不意味着同一件事。

     

语义是分配资源标识符并用表示填充这些资源的行为的副产品。服务器或客户端软件在任何时候都不需要知道或理解URI的含义。 ...

通过使用/user/1/after/2/user/1/reorder/2之类的URI,您不仅要针对不同的资源,而且您必须针对条目的每个位置变化发出请求,除了客户端需要了解该URI的语义生成一个。如上所述,服务器应教客户如何实现目标。这样,它应该为客户提供所有可能的选择。在这种情况下,如果您的集合包含10.000个条目,则需要为每个条目提供2个链接以逐步移动条目,或者为每个条目提供9999个链接以将元素移至目标位置。特别是后一种情况会产生巨大的响应。

我反对提出的解决方案的另一个原因是,在对集合中的条目进行重新排序时,除非您将位置编号的一部分包含在其中,否则URI以及各个条目本身的实际数据完全不会受到影响。 URI(我不建议将其作为URI的更改)不建议将URI作为目标,即使该资源所代表的实际内容仍然相同,现在也将其作为目标。因此,URI应该保持稳定。

关于以正确的顺序显示条目,应选择相应的媒体类型,并且需要所有各方的支持。存在诸如application/vnd.collection+json之类的媒体类型,尽管JSON基本类型不能保证顺序正确。在这里,您可能需要一种自定义的媒体类型,该媒体类型应包括应作为客户应遵循的字段信息的位置。幸运的是,其他表示形式(例如XML或纯文本)不会受到这种暗示的影响。

总结一下,让服务器教客户应该知道什么,并为他们提供可以使用的链接和数据。像设计Asbjørn UlsbergJim Webber所解释的状态机一样,设计交互流程。通过提供链接关系,您可以将URI从其语义目的中分离出来,这不会迫使客户端解析和解释URI。关于条目的实际排序,必须特别注意表示格式,因为并非所有格式都像JSON那样自然地遵循排序。