现代移动和Web应用程序旨在提供令人愉快和无缝的用户体验。作为用户,我们的要求越来越高,我们期望每天与之交互的移动应用程序都能获得出色的用户体验。例如,如果我们点击社交媒体应用程序上的点赞按钮,但互联网连接恰好在那个特定时刻中断,我们希望应用程序会负责重试,并让连接看起来从未中断。为了提供这种用户体验,前端开发人员传统上必须实现复杂的机制,用于在本地缓存中存储数据、自动恢复连接、使用指数退避进行重试、将数据同步到云并将其与安全的冲突解决方案合并。要实现这样的体验并不容易,我们从开发人员那里听到,他们宁愿把时间花在新功能上,而不是把时间花在这种毫无区别的繁重工作上一遍又一遍。
AWS AppSync是适用于移动和Web应用程序的GraphQL无服务器后端。它通过内置计算层提供灵活可靠的API来运行查询、突变和订阅,从而安全地访问、操作和组合来自任何应用程序的一个或多个数据源的数据。在客户端设备上,Amplify数据存储区提供了一种熟悉的编程模型,用于利用共享和分布式数据,而无需为离线、实时和在线方案编写额外代码,这使得处理分布式、跨用户数据与处理仅本地数据一样简单。
今天,我们将分享一个参考应用程序和架构,演示如何使用前端带有Amplify数据存储区的React Native和后端带有Amazon DynamoDB的AWS AppSync构建具有内置脱机和云同步功能的现代移动应用程序。
Amplify Datastore是一个在移动设备或Web浏览器内部运行的客户端,它提供一个API供开发人员与之交互。它充当持久存储库,将数据存储在本地,并通过GraphQL查询、突变和订阅在后台自动将其同步到云。与数据存储区客户端的任何交互始终针对本地数据,而同步、冲突检测、版本控制和日志记录由同步引擎和AWS AppSync在后台自动处理。值得一提的是,数据同步到云是Datastore的一项可选功能,如果需要,您可以在没有AWS帐户的情况下以仅本地独立模式使用它。
另一个重要的亮点是,开发人员不需要熟悉像Apollo或Relay这样的GraphQL库。他们只需使用标准函数调用数据存储区API,客户端会在后台自动将这些操作转换为GraphQL查询、突变和订阅,以便与AWS AppSync API端点进行交互。数据存储区中提供了以下API,可方便地操作您的数据:
观察-订阅使用AppSync实时功能监听模型更改的功能。
清除-从本地存储中删除所有数据,这在用户注销以清除本地数据时非常有用。
使用Amplify CLI中的模型生成工具,开发人员首先将他们的数据模型定义为标准的GraphQL架构,CLI会自动生成本机代码中的模型,还会创建GraphQL语句(查询、突变和订阅),这样您就不必手动编写代码。此外,通过使用Amplify CLI中的PUSH命令,开发人员可以使用DynamoDB表和一组GraphQL解析器自动调配AppSync API,以便根据定义的架构对数据执行CRUD操作。所有这些都不需要编写一行后端代码。
我们决定构建一个现代的无服务器销售点(POS)实现,作为展示上述所有服务的移动应用程序。对于离线功能,还有什么比关键业务应用程序更好的使用案例呢?该应用程序处理销售,即使全天出现小范围的互联网中断也需要继续工作。商店员工应该继续处理交易并为客户服务,而不必担心互联网连接不良。
我们为Point of Sale应用程序选择了一个咖啡馆主题,所以让我们来了解一下咖啡师使用移动应用程序的用户体验。这一切都从主屏幕开始,咖啡师可以在接受客户订单时将产品添加到购物车中:
当顾客准备好付款时,咖啡师导航到结账屏幕,在那里订单摘要与行项目、数量和税一起显示。按Checkout按钮将使用数据存储区保存订单,并将您带回主屏幕。
最后,用户可以浏览按日期分组的订单列表。这就是订阅数据实时更改变得非常有用的地方,因为只要销售点应用程序的任何用户添加新订单,此列表就会动态填充。无需手动刷新列表,数据存储区将观察和检索异步新订单,并自动更新应用程序本地存储,从而使订单列表始终保持最新。
该应用程序提供流畅的用户体验,因为向购物车添加产品快速且响应迅速,即使网络不可用,用户界面也不会出现延迟。这是可能的,因为UI正在与Amplify Datastore交互,只要有网络连接,Amplify Datastore总是在本地访问数据,并在后台将更改同步到云。虽然这是一个简单的应用程序,没有复杂的计算要求,但关键的亮点是,通过使用Amplify数据存储区构建具有可靠和高效的数据处理的令人愉快的响应用户体验是多么简单。
这一切都从GraphQL模式定义开始。开发人员在Graphql.schema文件中定义他们的应用程序数据模型,Amplify用本地语言为本地数据存储生成所有必要的构造。让我们看一下销售点应用程序的架构:
键入order@model{id:id!合计:浮点小计:浮点税:浮点创建日期:字符串!lineItems:[LineItem]@Connection(name:";OrderLineItems";)}type LineItem@model{id:id!数量:INT订单:Order@Connection(Name:";OrderLineItems";)product:product@Connection Description:String Price:Float Total:Float}type Product@model{id:id sku:string name:string Price:Float image:string}。
请注意@model和@connection指令,它们是Amplify抽象,允许开发人员快速创建应用程序的后端,包括DynamoDB表和GraphQL解析器来操作您的数据。@Connection指令特别用于定义模型之间的关系,例如“有一个”、“有多个”和“属于”。在本例中,我们的模型定义一个订单有多个LineItem,一个LineItem属于一个Order和一个Product。
异步函数submitOrder(Order){const now=new date().toISOString();//保存订单表头const Neworder=等待DataStore.save(new order({total:order.total,subtotal:order.subtotal,Tax:order.Tax,createdAt:Now,}));//保存每个行项目const Promises=order.lineItems.map(lineItem=>;{return DataStore.save(new LineItem({qty:lineItem.qty,description:lineItem.description,Price:lineItem.Price,Total:lineItem.total,order:neworder,//按订单关联产品:lineItem.product,//关联到产品});});等待Promise.all(Promise.all(Promises);}。
这有多简单?想象一下,如果我们不使用Amplify Datastore,并且必须针对Internet不可用实现错误处理逻辑,并将数据保存在本地以备以后同步到云中,那么代码会是什么样子。它将比上面的代码复杂得多。
当您有多个客户端向后端发送并发事务时,客户端总是有可能同时尝试更改同一项。这就是冲突解决方案派上用场的地方,也是开发人员开箱即用数据存储区的另一项AppSync功能。
让我们回顾一个更具体的示例,说明冲突解决在销售应用程序中的哪些方面是有用的:假设两个不同的咖啡师正在尝试更新产品目录,以更改产品的属性。一是更新产品定价,二是更新产品形象。当他们这样做的时候,他们两个突然都碰巧在同一时间更新了相同的产品:
AppSync允许两次更新都成功,从而优雅地解决了冲突。此策略称为Automerge,当在DynamoDB数据源中启用冲突解决时,它是默认策略。它主要使用GraphQL类型和字段信息来检查更新,并将其与已写入表的当前项进行比较。
您可以将此策略更改为使用乐观并发将版本检查应用于整个对象,其中写入数据库的最新项目使用针对传入记录的版本检查。或者,对于希望更好地控制冲突解决策略的开发人员,您可以使用Lambda函数,在该函数中,您可以在合并或拒绝更新时为冲突定义任何自定义业务逻辑。
当AppSync突变更改版本化的项目时,该更改的记录将存储在针对增量更新进行优化的Delta DynamoDB表中。此表的目的是允许客户端使用一个可能包含过多记录的基本查询的结果对其本地存储进行消重数据处理,然后仅接收自上次查询(增量更新)以来更改过的数据。增量同步表在您的AWS帐户中可见,并由Amplify数据存储区和AppSync解析器自动更新,开发人员无需执行任何操作即可填充该表。
这对销售点应用程序意味着什么?用户首次打开应用程序时,数据存储区通过查询未指定lastSync值的AppSync来提取订单,因此GraphQL解析器将从主Orders表中检索数据。
数据存储区自动跟踪并包括lastSync值,以便后续调用从后端获取订单。这称为增量查询,它仅使用增量同步表从该客户端提取自上次同步以来已更改的数据。它比转到主表更高效,因为增量同步表是专门为基于时间戳的查询而设计的。
增量同步表提供由AppSync解析器针对每个突变保持最新的日志。使用DynamoDB TTL属性定期逐出表上的项目,以防止该表积累陈旧数据。这允许客户端在从脱机状态切换到在线状态时高效地提取数据。“软删除”是AppSync的Delta Sync实现与DynamoDB数据源一起提供的另一个有趣的特性,这意味着删除的项目在基本表中使用Tombstone标志保留一段可配置的时间。这使开发人员有机会实现“Undelete”功能,通过在永久删除项目之前删除BaseTableTTL属性来处理意外删除。
借助AWS AppSync和Amplify Datastore,前端开发人员只需使用熟悉而简单的编程模型编写几行代码,即可构建现代应用程序,从而提供令人愉快、快速且响应迅速的用户体验。AppSync通过提供在高度可扩展的DynamoDB表中存储数据的托管GraphQL API端点为您的后端提供支持,而Amplify数据存储区通过提供强大的数据处理和足智多谋的同步引擎为您的客户端应用程序提供支持。
转到GitHub存储库,探索我们构建的销售点应用程序代码,并将其用作启动您自己的REACTION原生移动应用程序的示例:https://github.com/aws-samples/aws-appsync-refarch-offline.。您可以亲身体验,在几分钟内部署移动前端以及您AWS账户中的所有后端服务。
我们迫不及待地想知道您下一步将使用AWS AppSync和Amplify数据存储区构建什么!