REST API-特定于移动设备的挑战


25

我正在移动端上开发一个新的iOS应用程序项目。正在进行一些体系结构更改,事实证明,我们将不得不依赖自定义构建的私有API,该API将由我们正在构建的应用程序以及网站等其他客户端使用。

正在设计的API遵循映射到HTTP动词的以资源为中心的URI和CRUD操作的Rest样式。像:

GET www.example.com/books
DELETE www.example.com/books/482094
POST www.example.com/users/6793

问题在于,这种风格通常导致移动客户端需要执行许多请求来加载单个应用程序屏幕或管理单个用户UI操作。这将导致应用程序处于加载模式8秒钟,直到拥有所需的一切为止。缓慢且无响应的应用程序。

移动客户端在连接方面有严重的限制,因此理想情况下,我们应遵循以下规则:

1个屏幕== 1个API调用

1个保存== 1个API调用。

在许多情况下,这会使您与REST设计原则发生冲突,例如:

  • 假设您的应用离线了一天,您需要与后端数据库的四个表进行同步,并且您需要像 www.example.com/sync_everything?since=2015-07-24
  • 可以说有一个屏幕,用户可以在其中编辑许多对象,例如在待办事项列表中勾选任务。应该有一种方法可以在一个批处理API调用中编辑所有这些任务记录,而不是每次编辑都可以一个API调用。
  • 假设有一个混合了来自ORDER,SALESMEN和PRODUCT数据库表的信息的屏幕,我应该一次调用而不是三个调用来获取该数据。

这样做的风险是,我们最终可能会获得最宁静的API,以及最无用的无响应移动应用程序。

问题是我只是那里的新承包商,我需要的是可以帮助我阐明这些要点的东西,一些受到尊敬的消息来源的文章等等。主要参与者在针对其移动客户端的REST风格上妥协(例如:通过使用复合聚合API端点)。

或针对此一般问题的任何解决方案。谢谢!


3
听起来您的问题可能是,“ API如何在保留REST样式的同时传递相似或不同类型的对象和嵌入式对象的集合?” 我了解您的问题吗?
joshp

我相信一般的答案是,每个REST调用都需要采用各种可选参数,因此它既灵活又相对直观。同步情况总是很棘手,但是对于常规页面,您通常会查看多个相同类型的调用,即所有GET,对吗?
Ixrec

1
我认为,当问题是缺少并行请求采用API是错误的解决方案– 8个小请求在不必等待时,并不比一个大请求差很多。您可以切换到HTTP / 2吗?或者至少使用HTTP / 1.1流水线?
阿蒙(Amon)

另请参阅:用于在REST Web服务中处理批处理操作的模式?。关键是确定可以将哪些类型的命令(以及在什么前提下)一起批处理而不会发生冲突,然后创建批处理订单的JSON表示形式,然后将其发送出去。它失去了对REST的主要吸引力,即它的可缓存性,但可缓存性并不总是与所有类型的应用程序相关。请注意,如果存在逻辑依赖性,则批处理/并发性不适用。
rwong

类似于中间人需要按顺序执行多个操作(对每个前面的操作有非平凡的逻辑依赖性)的情况,类似于“存储过程”,它在那个中间人中执行而不是在数据库内部执行。在下面,允许中间人根据需要将单个“存储过程”调用转换为尽可能多的RESTful请求,但这是中间人的实现细节。
rwong

Answers:


27

正在设计的API遵循映射到HTTP动词的以资源为中心的URI和CRUD操作的Rest样式。

这是您的问题。

您已经将资源限制为(我假设)数据库中的模型。因此,加载所有这些资源需要很长时间,因为您的服务器没有数据库中没有表示形式的资源概念。

例如可能有

www.example.com/books/482094
www.example.com/books/582045
www.example.com/books/427454
www.example.com/books/319343

必须全部加载才能获得我的图书馆

这不是RESTful设计的问题,这实际上是REST反模式。REST中绝对没有任何内容可以说我们的资源必须与您系统中的任何其他内容(包括数据库模型)进行一对一映射。

解决方案是创建更多资源,以更好地匹配您要加载的资源。如果您有5个资源总是在一起使用,则创建一个新资源,其中包含这5个资源的信息。

你应该有这样的东西

www.example.com/users/334/my_library

只会为该用户加载所有书籍。“ my_library”不是数据库中的模型,但它是一种资源。服务器基于数据库中的模型创建它,但是没有一对一映射,并且服务器可以灵活地创建此资源而无需更改数据库模型。

您可能也有

www.example.com/users/334/favioured_books
www.example.com/users/334/books_ordered_last_week
www.example.com/users/334/wishlist

在您的数据库或域空间中,它们都不必作为模型存在。

人们普遍误解这是错误的做法,因为像Rails这样的框架教会人们以一对一的方式将资源映射到域空间中的模型,该模型再一次与数据库行进行一对一的映射。这不是必需的,也不建议这样做。

资源应该是众多,便宜且轻巧的。创建它们应该很容易,并且应该从您的域模型中抽象出来。如果您发现需要一个新的,则只需创建一个新的。如果这样做有问题,那是您的框架故障而不是REST的故障。

现在,与此有关的最大警告是您的框架是否允许您执行此操作。诸如Rails和Django之类的框架已经采用了“一对一”映射的方法,以“节省时间”,因此很难做到这一点。但这是框架的缺陷,而不是RESTful设计的缺陷。

这是吉姆·韦伯(Jim Webber)讨论的更多细节(包括在Rails中的一些挖掘!)

https://yow.eventer.com/yow-2011-1004/domain-driven-design-for-restful-systems-by-jim-webber-1047


这是非常有趣的,我完全同意这一点,但是可悲的是,我不是使用API​​的人,并且几乎没有办法影响它(如果有)。许多人都会使用该“反模式”(出于多种原因,框架限制是其中之一),他们只是使用URI定义来清晰地思考他们的数据库。API端点只是可视化其数据库的另一种方式...而且,在某些情况下,由于对象的确不同,因此创建诸如您描述的资源之类的资源很困难,仅命名它们会导致非常模糊的术语。
MikaelW 2015年

从效率的角度出发,他们同意,如果移动屏幕非常慢(并且只有在发生这种情况时),才可能进行一些组合调用,但是它们将位于环绕API的组件中(而不是API本身),将仅由移动客户端使用,并且不会被视为核心API(核心域)的一部分。
MikaelW 2015年

@MikaelW,你是对的。甚至Cormac所说的都是理想的方案,有时您使用的API需要参与许多其他系统(台式机,移动设备,Web,计划作业,旧系统等)。这种API需要非常灵活,它提供资源以尽可能地参与许多可能性,但不能满足一个使用者的所有特定性能需求。在这种情况下,您
别无选择
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.