引言:为什么选择 Swift 用于 REST API?
Swift 不仅仅是移动应用开发的语言。得益于 Vapor 和 Kitura 等框架,你可以在服务器端创建功能完备的 REST API。如果你的 iOS 应用已经使用了 Swift,这一点尤为有用:你可以用同一种语言编写客户端和服务器端代码,从而减少开发时间并简化代码维护。
在本文中,我们将使用 Vapor 框架(Swift 服务端开发最流行的解决方案)创建一个简单的 REST API。我们将配置服务器、添加 CRUD 操作的路由并进行测试。整个过程不超过 30 分钟。
要求: macOS 或 Linux,已安装 Swift 5.8+(或更新版本),对 HTTP 和 JSON 有基本了解。
第 1 步:安装和设置 Vapor 项目
Vapor 提供了便捷的 CLI 工具,方便快速入门。通过 Homebrew 安装:
brew install vapor然后创建一个新项目:
vapor new MyAPI --template=apicd MyAPI--template=api 标志会创建一个带有 REST API 最小结构的脚手架。项目创建完成后,在 Xcode(或任何编辑器)中打开:
open Package.swift项目结构包括:
Sources/App/— 主要逻辑(路由、控制器、模型)。Sources/App/routes.swift— 路由注册。Sources/App/configure.swift— 应用配置。Package.swift— 依赖项(已包含 Vapor)。
如果你使用 Xcode,它会自动下载依赖项。在终端中运行 vapor build 进行构建。
第 2 步:创建数据模型和数据库
对于 REST API,我们需要一个模型。让我们创建一个简单的 Task 模型,包含字段:id、title、completed。在 Vapor 中,模型通常继承自 Model(Fluent ORM)。
创建文件 Sources/App/Models/Task.swift:
import Fluentimport Vapor
final class Task: Model, Content { static let schema = "tasks"
@ID(key: .id) var id: UUID?
@Field(key: "title") var title: String
@Field(key: "completed") var completed: Bool
init() {}
init(id: UUID? = nil, title: String, completed: Bool = false) { self.id = id self.title = title self.completed = completed }}现在为数据库表创建一个迁移。创建文件 Sources/App/Migrations/CreateTask.swift:
import Fluent
struct CreateTask: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { database.schema("tasks") .id() .field("title", .string, .required) .field("completed", .bool, .required) .create() }
func revert(on database: Database) -> EventLoopFuture<Void> { database.schema("tasks").delete() }}将迁移添加到 configure.swift:
app.migrations.add(CreateTask())默认情况下,Vapor 使用 SQLite(项目文件夹中的一个文件)。如果你想要 PostgreSQL 或 MySQL,请在 configure.swift 中更改设置,但对于快速入门,SQLite 完全够用。
第 3 步:注册 REST API 路由
现在创建一个控制器来处理请求。创建文件 Sources/App/Controllers/TaskController.swift:
import Vaporimport Fluent
struct TaskController: RouteCollection { func boot(routes: RoutesBuilder) throws { let tasks = routes.grouped("tasks")
tasks.get(use: index) // GET /tasks tasks.post(use: create) // POST /tasks tasks.grou