探索 Swift 服务端生态
Explore the Swift on Server ecosystem
2024年6月10日
一句话判断
Apple 用这场 Session 证明 Swift 在服务端不是实验项目——iCloud、Private Cloud Compute 都在生产环境跑着,生态工具链已经足够成熟。
这场 Session 讲了什么
这场 Session 全面介绍了 Swift 在服务端的应用现状和生态体系。开场就给出了有力的数据:Apple 内部的 iCloud Keychain、Photos、Notes、App Store 处理流水线、SharePlay 文件共享,以及全新的 Private Cloud Compute 服务,都在用 Swift 处理每秒百万级请求。
内容分三个部分。第一部分解释了 Swift 适合服务端的原因:ARC(而非 GC)带来可预测的内存使用和快速启动、编译期类型安全消除运行时错误、一流的并发支持。第二部分是实操演示:用 Swift OpenAPI Generator + Vapor + PostgresNIO 构建一个事件管理服务。第三部分介绍了 Swift Server Workgroup 的组织方式和生态包的孵化流程。
演示部分很有说服力。从一个 OpenAPI YAML 定义出发,通过 Swift OpenAPI Generator 自动生成类型安全的 server/client 代码,再用 Vapor 作为 HTTP 传输层,PostgresNIO 作为数据库驱动,整个过程不到半小时就搭起了一个可运行的服务。PostgresNIO 1.21 新增的 PostgresClient 提供了内置连接池,利用结构化并发实现网络故障自动恢复。
值得深挖的点
PostgresNIO 的连接池与结构化并发
PostgresNIO 1.21 引入的 PostgresClient 不只是一个数据库驱动,它是一个完整的连接管理方案。内置连接池会自动预热连接、在多个连接间分发查询、在网络故障时利用结构化并发进行重连。
Session 中展示的使用模式是:创建一个 PostgresClient 实例,用 discarding task group 同时运行 PostgresClient 和 Vapor application。run() 方法会阻塞当前任务直到客户端结束,所以需要用 task group 来并行管理多个长期运行的服务。这个模式和传统服务端框架中”阻塞主线程等待数据库连接”的方式完全不同,体现了 Swift 并发模型的优势——你可以用结构化的方式管理多个并发的生命周期。
Swift OpenAPI Generator 的声明式服务开发
Swift OpenAPI Generator 的思路和 TypeScript 生态的 OpenAPI 工具链类似:用一份 YAML 定义 API 规格,自动生成 Swift 的类型安全代码。生成的代码包括请求/响应的类型定义和协议接口,你只需要实现协议方法即可。
这种模式的好处是 API 定义成为 single source of truth。前后端(或客户端和服务端)可以共享同一份 OpenAPI 定义,通过代码生成确保类型完全匹配。当 API 需要变更时,修改 YAML 后重新生成代码,编译器会指出所有需要更新的地方。这比手动维护两边的模型类型要可靠得多。
代码片段
场景一:用 OpenAPI 定义和实现事件服务
# openapi.yaml
openapi: "3.0.3"
info:
title: EventService
version: "1.0"
paths:
/events:
get:
operationId: listEvents
responses:
"200":
description: 事件列表
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Event"
post:
operationId: createEvent
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
responses:
"201":
description: 创建成功
"400":
description: 请求无效
components:
schemas:
Event:
type: object
properties:
id:
type: string
name:
type: string
attendees:
type: array
items:
type: string
# 坑点:YAML 缩进错误会导致生成代码失败
# 建议用 OpenAPI 编辑器工具(如 Swagger Editor)验证后再生成
场景二:实现生成的 APIProtocol
import OpenAPIRuntime
import OpenAPIVapor
struct EventServiceHandler: APIProtocol {
let postgresClient: PostgresClient
// 实现 listEvents 方法
func listEvents(
_ input: Operations.listEvents.Input
) async throws -> Operations.listEvents.Output {
// 使用 PostgresClient 查询数据库
var events: [Components.Schemas.Event] = []
let rows = try await postgresClient.query(
"SELECT id, name, attendees FROM events"
)
for try await row in rows {
let id = try row.decode(String.self, at: 0)
let name = try row.decode(String.self, at: 1)
// 注意:AsyncSequence 会自动预取行,提升性能
events.append(.init(id: id, name: name, attendees: []))
}
return .ok(.init(body: .json(events)))
}
// 实现 createEvent 方法
func createEvent(
_ input: Operations.createEvent.Input
) async throws -> Operations.createEvent.Output {
guard case .json(let event) = input.body else {
return .badRequest
}
try await postgresClient.query(
"INSERT INTO events (id, name) VALUES ($1, $2)",
[event.id, event.name]
)
return .created
// 坑点:PostgresClient 的 query 方法参数需要显式类型
// 否则可能因为类型推断歧义导致编译错误
}
}
场景三:用 Task Group 并行运行服务和数据库客户端
import Vapor
import PostgresNIO
@main
struct Server {
static func main() async throws {
// 创建 PostgresClient
let postgresClient = PostgresClient(
host: "localhost",
port: 5432,
username: "postgres",
database: "events",
password: "password"
)
// 创建 Vapor 应用和传输层
let app = Vapor.Application()
let transport = VaporTransport(routesBuilder: app)
// 注册服务处理器
let handler = EventServiceHandler(postgresClient: postgresClient)
try handler.registerHandlers(on: transport, serverURL: URL(string: "/")!)
// 使用 discarding task group 并行运行
try await withDiscardingTaskGroup { group in
// 子任务 1:运行 PostgresClient
group.addTask {
try await postgresClient.run()
// run() 方法会阻塞直到客户端关闭
}
// 子任务 2:运行 Vapor HTTP 服务器
group.addTask {
try await app.execute()
}
}
// 坑点:两个子任务中任何一个出错都会触发整个 group 退出
// 需要确保错误处理逻辑正确
}
}
最佳实践
- 迁移建议:如果你在考虑用 Swift 写服务端,从 OpenAPI Generator + Vapor 这个组合开始。OpenAPI 定义文件可以作为 API 文档和代码生成的双用途资产,投入产出比很高。PostgresNIO 是 Apple 和 Vapor 团队共同维护的,可以放心在生产环境使用。
- 编辑器选择:Swift 服务端开发不限于 Xcode。VS Code + Swift 扩展、Neovim 等 LSP 兼容编辑器都能获得完整的代码补全和调试体验。Session 中的演示全程使用 VS Code。
- 包管理:遵循 Swift Server Workgroup 的孵化流程,优先选择经过孵化认证的包。这些包在 API 兼容性、文档质量和长期维护方面有更好的保障。
还有什么值得关注
- Swift Server Workgroup 成立于 2016 年,是 Swift 社区最早的工作组,生态成熟度比很多人想象的要高
- Private Cloud Compute 是 Apple 全新的云服务架构,完全用 Swift 构建,代表了对 Swift 服务端能力的最高级别信任
- Swift Package Index 可以浏览所有经过审核的服务端相关包,是选型时的好起点