最近,我看到一条消息说,GitHub将其API从REST迁移到了GraphQL。 这让我真的对GraphQL及其提供的功能感到好奇。 介绍 GraphQL是一种新的API设计范例,于2015年由Facebook开源,但自2012年以来一直为他们的移动应用提供动力。它消除了当今REST API的许多低效率问题。 与REST相比,GraphQL API仅公开一个端点,并且API的使用者可以精确地指定所需的数据。 在iOS开发中,我们可以利用Apollo iOS客户端的优势对GraphQL服务器执行查询和变异,并以查询特定的Swift类型返回结果。 这意味着您不必处理解析JSON或传递字典并使客户端将值手动转换为正确类型的麻烦。 您也不必自己编写模型类型,因为它们是从UI使用的GraphQL定义生成的。 为什么选择GraphQL? REST API公开了多个端点,每个端点都返回特定的信息。 例如,我有以下两个端点: / classes:返回类列表。 / classes / id / students:返回参加此课程的学生列表。 现在,如果我想显示所有班级的列表以及两名参加该班级的学生。 有两种选择: 修改现有的API,使响应在每个班级中包含两名学生的信息。 多次致电/ classes / id / students以获取我想要的信息。 它们都不是一个好的解决方案,因为将来很难扩展。 但是,我可以在GraphQL的单个请求中简单地指定数据要求。 响应将包含一系列班级以及两名学生。 先决条件 在本文中,我想实现一个非常简单的应用程序,该应用程序显示班级列表以及班级中的老师和学生。 但是,在我们开始之前,仍有几件事要做。 首先,有必要配备GraphQL服务器,而Graphcool是一个完美的选择。 访问该网站并按照说明创建一个名为Schedule的项目。 此外,将以下代码添加到Graphcool控制台中以创建必要的架构。 type Class implements Node { id: ID! @isUnique title: String! createdAt: DateTime! updatedAt: DateTime! […]
如您所见,它看起来像其他数据库。 在屏幕右侧,您可以看到一些名为File和User的表。 这是预定义的表格,您无法删除它们。 在这里,表称为类型,并且全部实现Node类型。 尝试删除文件类型的代码块,然后单击预览更改,您将收到此错误: 现在,单击添加类型并添加新类型。 我将添加一个名为Girl的类型。 您可以看到带有锁定图标的3个字段:id,createdAt和updatedAt。 这3个字段是系统字段,并且是自动填充的,因此您无法进行修改。 现在,我们将打开操场来使用GraphQL做一些简单的例子。 我已经输入了一些数据。
重命名该新脚本以生成Apollo GraphQL API。 将以下代码片段复制到外壳程序: APOLLO_FRAMEWORK_PATH =“ $(分别找到$ FRAMEWORK_SEARCH_PATHS -name” Apollo.framework“ -maxdepth 1)” 如果[-z“ $ APOLLO_FRAMEWORK_PATH”]; 然后 echo“错误:在FRAMEWORK_SEARCH_PATHS中找不到Apollo.framework;请确保将框架添加到您的项目中。” 1号出口 科幻 cd“ $ {SRCROOT} / $ {TARGET_NAME}” $ APOLLO_FRAMEWORK_PATH / check-and-run-apollo-codegen.sh生成$(find。-name’* .graphql’)–schema schema.json –output API.swift 生成项目以完成安装。 3.添加架构文件: 接下来,您需要将GraphQL服务器的架构文件添加到项目中。 转到Graph.cool仪表板以获取端点链接。 这是格式为https://api.graph.cool/simple/v1/xxx的链接。 打开终端并输入以下内容: 阿波罗代码生成下载模式SIMPLE_API_ENDPOINT-输出schema.json 这会将文件名schema.json下载到您的计算机。 将此文件添加到Xcode项目的根目录。 现在让我们编码。 打开AppDelegate并将其添加到顶部 请忽略此愚蠢的UI,因为这只是一个小演示。 现在从GraphQL开始。 我们将创建一个扩展名为.graphql的文件,以保留所有GraphQL命令。 第一次运行apollo- codegen时 , 它将在项目的根文件夹中创建一个名为API.swift的文件。 尽管此文件已经在您的文件夹中,但是您仍然需要将其添加到项目中。 注意:请记住取消选中“ 复制项目”选项( 如果需要)。 […]
与Trulia的其他工程团队一样,iOS团队也了解与我们的整体架构相关的挑战。 我们处理了性能问题,发布延迟以及iOS功能与其他平台上的功能之间普遍缺乏对等的问题。 我们经常受到上游决策的负面影响,被迫提出变通办法和权宜之计,只会加重我们面临的许多挑战。 Trulia从单块架构过渡到微服务架构的决定为移动团队提供了一个机会,以永久解决我们的许多挑战,并通过实施GraphQL来偿还我们的一些技术债务。 技术债务:移动API 与整体交互所产生的问题可以追溯到我们的移动应用程序的创建。 这包括我们面临的最大挑战-我们在移动客户端上所需的数据通常分散在多种服务中,仅通过复杂的关系进行连接。 这种低效的配置产生了多个请求,返回了我们不需要的数据,并浪费了资源。 我们通过创建外观REST接口解决了该问题。 外墙处理了处理整体架构的各个部分以及将来自各种来源的数据序列化为一致结构的所有复杂问题,移动客户端可以轻松使用它们。 虽然这简化了我们与整体的交互,但也带来了其他挑战。 移动应用程序需要访问的任何新API也将需要由Facade实现,从而导致更长的总体开发时间。 上游API接口的更改也需要应用于外观,这需要双重维护。 负责各种API和外观的团队的路线图通常不一致,导致Web应用程序和移动应用程序之间存在差异 在考虑转向微服务架构时,我们想了解如何在满足每个客户需求的同时保留外观的优点。 解决方案:GraphQL 我们决定使用基于GraphQL的API创建一个统一的接口,该接口仅以一致的格式向各个客户端提供必要的数据。 单一界面的使用鼓励所有利益相关者参与并为总体架构和领域模型的设计做出贡献,从而确保满足每个团队的需求。 这种合作的例子发生在Trulia Neighborhoods的模式设计的早期。 我们意识到,各个客户端对图像压缩类型的偏好有所不同-iOS支持HEIF压缩,Android首选WebP,而移动Web则首选png。 GraphQL允许我们添加参数,以便每个客户端可以传递其首选的压缩格式以获取远程图像资源。 此外,在GraphQL下进行统一提供了将通常在每个客户端上实现的业务逻辑转移到GraphQL层中的解析器的机会。 当业务规则指示如何显示数据更改时,这消除了客户更新代码的要求。 积分 事实证明,使用Apollo提供的SDK和工具来创建和处理对GraphQL服务器的请求,实施GraphQL是一个简单的过程。 该工具集使我们能够使用GraphQL语法编写查询,并自动生成在每个唯一客户端中执行查询所必需的代码。 虽然我们通过单一查询语言进行统一,但iOS查询是在Swift中生成的,Android查询是在Java / Kotlin中生成的,而Web查询是在TypeScript中生成的。 安卓系统 public final class LocationQuery implements Query { private final LocationQuery.Variables variables; public LocationQuery(@Nonnull Input id) { … } @Override public LocationQuery.Data wrapData(LocationQuery.Data data) { […]
作为iOS开发人员,我们通常依靠URLSession来为我们的网络层编写单元测试。 鉴于GraphQL和Apollo抽象了我们的网络层并充当了网络资源的黑匣子,我们不能依靠典型的URLSession模拟策略来实现最大的单元测试覆盖率。 让我们使用一个公共的GraphQL API创建一个示例应用程序并编写一些单元测试。 我们的示例应用程序将是一个简单的表格视图主详细信息应用程序,该应用程序列出了仓库的国家/地区,并可以在详细信息页面上加载有关它们的详细信息。 首先,让我们考虑一下如何构造数据。 考虑到母版页仅需要一个国家的几个数据点,而详细信息页将需要更多有关特定国家的数据。 这是使用GraphQL的原因之一,我们实际上可以为单独的用例定义单独的模型。 这种仅获取给定屏幕所需内容的技术可以为我们的应用程序提供性能改进,减少我们的TTI(交互时间)并改善用户体验。 我们将定义一些GraphQL片段来设计模型。 在Swift结构中定义数据模型后,我们应该为这些对象从GraphQL模型中创建可选的初始化器。 这实际上将使解析我们的数据并将其转换为我们服务中的域模型变得简单。 Apollo将所有内容都设为可选everything,因此我们所有的初始化程序都将失败。 您可能知道从GraphQL数据中删除可选性的更好方法,如果需要,请发表评论。 在进行转换以处理可选性时,我们将依靠flatMap和compactMap 。 最初发布在 gist.github.com上 。
现在,我们有了一个可以正常运行的快速服务,该服务返回了名称空间域模型,我们可以为此类设计一种测试策略。 首先,我们要考虑对GraphQL进行完全模拟是否值得。 例如,您可以创建一个符合ApolloInterface的模拟对象,然后从那里编写单元测试。 相反,我们将模拟Apollo客户端,并使用残存的原始JSON实际执行Apollo查询。 这是理想的,因为我们实际上测试了代码如何与Apollo交互。 此外,您可以使用JSON和模拟的NetworkTransport对象在单元测试中模拟失败的网络或解析状态,从而使我们可以获得有关World.Store网络对象的更多测试范围。 此测试策略是从Apollo-iOS测试套件中借用的,您可以在此处查看源代码。 首先,让我们看一下模拟的NetworkTransport对象: 最初发布在 gist.github.com上 。
编写iOS应用的典型方法 大多数现代移动应用程序只是JSON的漂亮表示形式-新闻订阅源,实时比分,即时通讯程序等。 通常,应用程序执行对REST端点的请求,接收JSON响应,将其转换为模型对象,最后将其显示在屏幕上。 iOS开发人员已经对这种方法感到满意了几年,因此现在有许多库,API和技术可用来构建此类应用程序。 但是感觉应该有一些改进的空间。 让我们找出弱点并考虑更好的解决方案。 REST怎么了 当iOS开发人员开始使用基于网络的功能时,通常会为他们提供一个现有的服务器端点,并希望有详尽的文档。 如果API针对移动客户端进行了优化,这始终是个好消息,但通常它只是服务器模型的一种表示形式。 问题在于应用程序通常需要的数据集与端点提供的数据略有不同。 假设我们正在构建一个GitHub团队浏览器,我们需要显示团队成员姓名列表以及他们的仓库名称,但是只有一个端点可以返回团队成员的完整信息以及ID。回购。 当然,我们可以要求后端团队引入新的端点或特殊参数,以仅获取对象或字段的子集: GET / members / 1213?listPreview = true GET / membersAndRepos / 1213 但这不是一个好的解决方案,因为: 后端团队可能不可用; 实现,测试和记录更多端点需要花费时间; 应用需求可能会发生变化,因此这些添加将变得多余。 因此,自然必须发生的事情是在响应中下载不必要的数据并执行过多的请求。 如果客户端应用程序有一种很好的方法来指定所需的数据怎么办? 什么是GraphQL以及为什么很酷 GraphQL是使之成为可能的方法。 根据官方网站的说法,“ GraphQL是API的查询语言,并且是服务器端运行时,用于通过使用为数据定义的类型系统执行查询。 GraphQL不受任何特定数据库或存储引擎的束缚,而是由您现有的代码和数据支持。” GraphQL于2012年出生于Facebook。他们的移动团队正在研究新的提要,当时他们意识到现有技术远不适合移动应用程序-那时互联网连接速度很慢,因此优化查询将大大改善用户体验。 在内部成功之后,该团队于2015年开源了GraphQL。现在GraphQL是RFC规范,并且有多种语言的实现。 除了Facebook本身,一些大公司已经引入了GraphQL API:GitHub和Shopify。 顾名思义,GraphQL是图形的“查询语言”。 由于大多数现代应用程序内部的数据都可以表示为图形,因此GraphQL是一种便捷的解决方案。 关于GraphQL的最神奇的部分是它的简单流程: 描述您的数据。 询问您想要什么。 获得可预测的结果。 描述数据 每个GraphQL服务都有一个架构-服务器上可用数据的蓝图。 强大的类型是GraphQL模式特别酷的地方。 此外, schema.json文件的作用类似于服务器的文档。 继续我们的repos示例,我们可以有一个这样的模式: 输入用户{ 名称:字符串! avatarUrl:字符串 贡献的资料库:[资料库]! […]
这篇文章是在Swift中包装C库的多部分指南中的第一篇。 第1部分将逐步完成构建Swift项目的过程,该项目可以使用Swift Package Manager(SPM)与C库libgraphqlparser进行交互。 其他部分将介绍如何将C接口包装为使用起来更自然的Swift API。 在探索特定库的示例时,此处描述的相同技术可以应用于大多数其他C库。 自2016年以来,在Shopify,我们一直在移动应用程序中使用GraphQL。GraphQL提供的优于典型REST API的优势之一是它具有定义明确的架构。 可以利用GraphQL模式编写代表各种查询和变异的网络响应的强类型Swift代码。 这段代码编写起来很繁琐且容易出错,因此我们决定构建一个可自动生成代表您的GraphQL查询和变异的Swift模型的工具。 构建这样的工具的首要挑战之一是找到一种方法来解析GraphQL语法中定义的查询和变异,并将其转换为可由Swift代码理解的抽象语法树。 构建语法分析器并非易事。 幸运的是,GraphQL组织已经发布了一个用C ++编写的开源解析器。 Swift无法直接与C ++代码互操作,但是libgraphqlparser项目提供了一个纯C API,只需做一点工作,就可以在Swift中使用它。 libgraphqlparser库的标头中定义了一些功能,可以完全满足我们的需求。 从libgraphqlparser的C头文件 第一个函数将采用GraphQL查询字符串,并将其转换为查询的AST表示形式。 对于本教程,我们将仅使用graphql_ast_to_json(ast)将AST转换为JSON并打印结果。 设置基本软件包 SPM要求定义一个包装系统库的Swift软件包,但是由于没有Swift代码,因此无法直接构建该软件包。 为了验证该库可以导入到Swift代码中,基本包必须将包装器包作为依赖项导入。 让我们构建该基本软件包。 $ mkdir GraphQLParser $ cd GraphQLParser GraphQLParser $ swift软件包init –type可执行文件 安装库 安装libgraphqlparser可以通过从源代码构建或使用以下命令通过自制程序来完成。 $ brew安装libgraphqlparser 完成初始项目设置后,我们需要将代码公开给Swift。 由于这是针对macOS命令行应用程序的,因此我们可以使用Swift Package Manager(SPM)。 为了向Swift代码公开系统库,我们需要告诉编译器在哪里可以找到我们要使用的代码。 通常,这包括将动态库的位置和任何必需的头文件的位置通知编译器。 在这种情况下,动态库可能已安装到/usr/local/lib/libgraphqlparser.dylib ,并且头文件将已写入/usr/local/include/graphqlparser 。 SPM通过要求用户定义一个包装系统库的程序包并为该库提供模块映射来解决此问题。 约定是在这些程序包之前使用大写的“ C”作为前缀,因此该程序包将被称为“ Clibgraphqlparser”。 在与GraphQLParser文件夹相邻的目录中初始化此软件包。 GraphQLParser […]
我再看一下graphql,我试图理解为什么节省往返旅程对开发人员是有好处的。 请求的代价如此昂贵? 我来自网页开发背景。 让我们比较一个标准的rest api和一个graphql api。 我需要检索用户的个人信息和他们的朋友列表。 传统的restAPI可能需要2个电话,一个获取个人信息,一个获取朋友。 用graphql,我得到了一个请求相同的结果。 但是作为一个前端开发者,我希望我的页面有最短的停滞期。 我想尽可能快地渲染页面的一部分,而不是等待我所需要的所有信息,然后渲染页面。 现在从我的理解,graphql是部分创build解决移动应用程序API的问题。 有没有什么关于ios应用程序,使它更有利于一次加载所有的数据,而不是并行请求? 还是有什么我失踪?