使用Swift的GraphQL API:iOS和macOS逐步教程

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么选择 GraphQL 和 Swift?

现代 iOS 和 macOS 开发需要灵活高效的方式与服务器交互。传统的 REST API 经常导致过度获取(over-fetching,获取多余数据)或获取不足(under-fetching,数据不足)的问题。GraphQL 解决了这些问题,允许客户端在一次请求中只获取所需的数据。

在本教程中,我们将创建一个完整的 Swift 应用程序,与 GraphQL API 进行交互。您将学习如何配置项目、执行查询、变更以及处理错误。我们将使用 Apollo iOS 作为客户端——这是 Apple 生态系统中用于 GraphQL 最流行的库。

项目配置与安装 Apollo iOS

创建新项目

打开 Xcode 并创建一个新的 iOS 或 macOS App 项目。将其命名为 GraphQLDemo。

通过 Swift Package Manager 安装 Apollo iOS

  1. 在 Xcode 中,进入 File → Add Packages...
  2. 粘贴 Apollo 仓库的 URL:https://github.com/apollographql/apollo-ios.git
  3. 选择最新的稳定版本,然后点击 Add Package。
  4. 确保该包已添加到您的应用程序 target 中。

根据 GraphQL 模式生成代码

Apollo 使用代码生成来创建类型安全的类。为此,我们需要一个模式文件(schema.graphqls)和查询文件(.graphql)。

在项目中创建一个 GraphQL 文件夹,并将以下文件放入其中:

  • schema.graphqls — 下载您 API 的模式,或使用公共模式(例如 Countries GraphQL API)。
  • Queries.graphql — 包含您的查询的文件。

Queries.graphql 的内容示例:

query GetCountries {
  countries {
    code
    name
    capital
    currency
  }
}

现在,添加一个 Build Phase 用于代码生成。在 Xcode 中:Target → Build Phases → + → New Run Script Phase。粘贴以下脚本:

cd "${SRCROOT}/${TARGET_NAME}"
./Pods/Apollo/scripts/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=./schema.graphqls ./GraphQL/API.swift

注意: 在较新版本的 Apollo iOS 中,使用的是 apollo-ios-cli。建议查阅 官方文档 以获取最新说明。

执行 GraphQL 查询(Queries)

初始化 Apollo 客户端

创建一个用于管理 Apollo 的 manager。打开 NetworkManager.swift 文件:

import Foundation
import Apollo

class NetworkManager {
    static let shared = NetworkManager()
    
    private(set) lazy var apollo: ApolloClient = {
        let url = URL(string: "https://countries.trevorblades.com/")!
        return ApolloClient(url: url)
    }()
}

执行查询

现在,在我们的 ViewController 中执行 GetCountries 查询:

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        fetchCountries()
    }
    
    private func fetchCountries() {
        NetworkManager.shared.apollo.fetch(query: GetCountriesQuery()) { result in
            switch result {
            case .success(let graphQLResult):
                if let countries = graphQLResult.data?.countries {
                    for country in countries {
                        print("\(country.name) - \(country.capital ?? "N/A")")
                    }
                }                

博客

书籍推荐