使用 Vapor 构建 Web 服务

本指南的源代码可以在 GitHub 上找到

安装 Swift

为了开始您的旅程,安装 Swift 以开始在 macOSLinuxWindows 上使用它。

提示:要测试您是否已安装 Swift,请从您的 shell 或终端应用程序运行 swift --version

Swift 捆绑了 Swift Package Manager (SwiftPM),用于管理 Swift 代码的分发。它允许轻松地将其他 Swift 包导入到您的应用程序和库中,使其成为任何 Swift 开发人员的宝贵工具。

Swift 采用 Apache License, Version 2.0 许可。

选择 Web 框架

多年来,Swift 社区创建了几个 Web 框架,旨在帮助构建 Web 服务。本指南重点介绍 Vapor Web 框架,它是社区中流行的选择。

安装 Vapor

首先,您需要安装 Vapor 工具箱。如果您已经在 macOS 上安装了 Homebrew,请运行

brew install vapor

如果您在不同的操作系统上运行,或者想从源代码安装工具箱,请参阅 Vapor 文档,了解如何操作。

创建项目

然后,在您想要创建新项目的目录中的终端中运行

vapor new HelloVapor

这会拉取一个模板,并询问您一系列问题,以创建一个简单的项目,其中包含您入门所需的一切。本指南将创建一个简单的 REST API,您可以向其发送和接收 JSON。因此,对所有其他问题回答“否”。您将看到项目创建成功

A New Vapor Project

导航到创建的目录,并在您选择的 IDE 中打开项目。例如,要使用 VSCode,请运行

cd HelloVapor
code .

对于 Xcode,运行

cd HelloVapor
open Package.swift

Vapor 的模板包含许多已为您设置的文件和函数。configure.swift 包含配置应用程序的代码,routes.swift 包含路由处理程序代码。

创建路由

首先,打开 routes.swift 并创建一个新路由,通过在 app.get("hello") { ... } 下方声明一个新路由,向任何访问您站点的人打招呼

// 1
app.get("hello", ":name") { req async throws -> String in
    // 2
    let name = try req.parameters.require("name")
    // 3
    return "Hello, \(name.capitalized)!"
}

以下是代码的作用

  1. 声明一个新的路由处理程序,注册为对 /hello/<NAME>GET 请求。: 表示 Vapor 中的动态路径参数,它将匹配任何值,并允许您在路由处理程序中检索它。app.get(...) 接受一个闭包作为最后一个参数,该闭包可以是异步的,并且必须返回 Response 或符合 ResponseEncodable 的内容,例如 String
  2. 从参数中获取名称。默认情况下,这会返回一个 String。如果您想提取另一种类型,例如 IntUUID,您可以编写 req.parameters.require("id", as: UUID.self),Vapor 将尝试将其转换为该类型,如果无法转换,则会自动抛出错误。如果路由尚未注册正确的参数名称,则会抛出错误。
  3. 返回 Response,在本例中是一个 String。请注意,您无需设置状态代码、响应正文或任何标头。Vapor 为您处理所有这些,同时允许您在需要时控制返回的 Response

保存文件并构建并运行应用程序

$ swift run
Building for debugging...
...
Build complete! (59.87s)
[ NOTICE ] Server starting on http://127.0.0.1:8080

https://127.0.0.1:8080/hello/tim 发送 GET 请求。您将收到响应

$ curl https://127.0.0.1:8080/hello/tim
Hello, Tim!

尝试使用不同的名称,看看它如何自动更改!

返回 JSON

Vapor 在底层使用 Codable,通过一个名为 Content 的包装协议来简化 JSON 的发送和接收,并添加了一些额外的功能。接下来,您将返回一个 JSON 正文,其中包含来自 Hello! 路由的消息。首先,在 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)
}

以下是此代码的作用

  1. 定义一个新的路由处理程序,用于处理对 /jsonGET 请求。重要的是,闭包的返回类型是 UserResponse
  2. 像以前一样获取名称并构造消息。
  3. 返回 UserResponse

保存并构建并再次运行应用程序,并向 https://127.0.0.1:8080/json/tim 发送 GET 请求

$ curl https://127.0.0.1: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)
}

这个新路由处理程序中重要的区别是

  1. 使用 app.post(...) 而不是 app.get(...),因为此路由处理程序是 POST 请求。
  2. 从请求正文中解码 JSON。
  3. 使用来自 JSON 正文的数据来创建新消息。

发送带有有效 JSON 正文的 POST 请求,并查看您的响应

$ curl https://127.0.0.1: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 上找到