使用 Vapor 构建 Web 服务
本指南的源代码可以在 GitHub 上找到
安装 Swift
要开始您的 Swift 之旅,请先安装 Swift,您可以在 macOS、Linux 或 Windows 上使用它。
提示:要测试 Swift 是否安装成功,请在终端或命令行中运行
swift --version
。
Swift 自带Swift 包管理器 (SwiftPM),用于管理 Swift 代码的分发。它让您能够轻松地将其他 Swift 包导入到您的应用程序和库中,是每个 Swift 开发者的重要工具。
Swift 采用 Apache License, Version 2.0 许可证。
选择 Web 框架
多年来,Swift 社区创建了几个用于构建 Web 服务的框架。本指南重点介绍 Vapor Web 框架,这是社区中的一个流行选择。
安装 Vapor
首先,你需要安装 Vapor 工具箱。 如果你已经在 macOS 上安装了 Homebrew,运行:
brew install vapor
如果你使用其他操作系统或想从源代码安装工具箱,请参阅 Vapor 文档 了解具体方法。
创建项目
然后,在终端中进入你想创建新项目的目录,运行:
vapor new HelloVapor
这会下载一个模板并询问你一系列问题来创建一个包含所有必需内容的简单项目。本指南将创建一个简单的 REST API,你可以向其发送和接收 JSON 数据。所以对其他问题都回答”否”。你会看到项目成功创建:
进入创建的目录并在你选择的 IDE 中打开项目。例如,要使用 VSCode,运行:
cd HelloVapor
code .
对于 Xcode,运行:
cd HelloVapor
open Package.swift
Vapor 的模板已经为你设置了许多文件和函数。configure.swift 包含配置应用程序的代码,routes.swift 包含路由处理代码。
创建路由
首先,打开 routes.swift 并在 app.get("hello") { ... }
下面创建一个新路由,向访问你网站的任何人说hello:
// 1
app.get("hello", ":name") { req async throws -> String in
// 2
let name = try req.parameters.require("name")
// 3
return "Hello, \(name.capitalized)!"
}
代码说明:
- 声明一个新的路由处理程序,注册为对
/hello/<NAME>
的 GET 请求。:
表示 Vapor 中的动态路径参数,它会匹配任何值并允许你在路由处理程序中检索它。app.get(...)
的最后一个参数是一个闭包,可以是异步的,必须返回Response
或符合ResponseEncodable
的类型,如String
。 - 从参数中获取名字。默认情况下,这返回一个
String
。如果你想提取其他类型,比如Int
或UUID
,你可以写req.parameters.require("id", as: UUID.self)
,Vapor 会尝试将其转换为该类型,如果无法转换则自动抛出错误。 - 返回
Response
,在这个例子中是一个String
。注意,你不需要设置状态码、响应体或任何头部信息。Vapor 会为你处理这些,同时也允许你在需要时控制返回的Response
。
保存文件并构建运行应用:
$ swift run
Building for debugging...
...
Build complete! (59.87s)
[ NOTICE ] Server starting on http://127.0.0.1:8080
向 http://localhost:8080/hello/tim
发送 GET 请求。你会收到响应:
$ curl http://localhost:8080/hello/tim
Hello, Tim!
试试用不同的名字,看看它是如何自动改变的!
返回 JSON
Vapor 在底层使用 Codable
,通过一个名为 Content
的包装协议来添加一些额外功能,使发送和接收 JSON 变得容易。接下来,你将在 Hello! 路由中返回带有消息的 JSON 主体。首先,在 routes.swift 底部创建一个新类型:
struct UserResponse: Content {
let message: String
}
这定义了一个新的符合 Content
的类型,匹配你想要返回的 JSON。
在 app.get("hello", ":name") { ... }
下面创建一个新路由来返回这个 JSON:
// 1
app.get("json", ":name") { req async throws -> UserResponse in
// 2
let name = try req.parameters.require("name")
let message = "Hello, \(name.capitalized)!"
// 3
return UserResponse(message: message)
}
代码说明:
- 定义一个新的路由处理程序,处理对
/json
的 GET 请求。重要的是,闭包的返回类型是UserResponse
。 - 像之前一样获取名字并构造消息。
- 返回
UserResponse
。
再次保存并构建运行应用,向 http://localhost:8080/json/tim
发送 GET 请求:
$ curl http://localhost:8080/json/tim
{"message":"Hello, Tim!"}
这次,你得到了 JSON 响应!
处理 JSON
最后,我们将介绍如何接收 JSON。在 routes.swift 底部,创建一个新类型来模型化你将发送到服务器应用的 JSON:
struct UserInfo: Content {
let name: String
let age: Int
}
这包含两个属性:名字和年龄。然后,在 JSON 路由下面,创建一个新路由来处理带有此主体的 POST 请求:
// 1
app.post("user-info") { req async throws -> UserResponse in
// 2
let userInfo = try req.content.decode(UserInfo.self)
// 3
let message = "Hello, \(userInfo.name.capitalized)! You are \(userInfo.age) years old."
return UserResponse(message: message)
}
这个新路由处理程序的重要区别是:
- 使用
app.post(...)
而不是app.get(...)
,因为这个路由处理程序是一个 POST 请求。 - 从请求主体解码 JSON。
- 使用 JSON 主体中的数据创建新消息。
发送带有有效 JSON 主体的 POST 请求,看看你的响应:
$ curl http://localhost:8080/user-info -X POST -d '{"name": "Tim", "age": 99}' -H "Content-Type: application/json"
{"message":"Hello, Tim! You are 99 years old."}
恭喜!你已经用 Swift 构建了你的第一个 Web 服务器!
本指南的源代码可以在 GitHub 上找到