Swift on Server Tour 4 构建 Post Controller

在本章中,我们将为 Post 创建一个 Controller,将 Route 和 Route Handler 都移动到这里,保持项目代码的整洁

Table of Contents

Controller 中的 Routing

在上一章中,下面两个和 Post 相关的 Route 和 Handler 都写在了 Sources/App/configure.swift

  • app.post("posts")
  • app.get("posts")

现在我们创建 Sources/App/Controllers/PostController.swift 文件,并将代码移动到这里

import Fluent
import Vapor
struct PostController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.group("posts") { posts in
posts.get(use: index)
posts.post(use: create)
}
}
func create(req: Request) async throws -> Post {
let postData = try req.content.decode(Post.CreateDTO.self)
let post = Post(content: postData.content)
try await post.create(on: req.db)
return post
}
func index(req: Request) async throws -> [Post] {
let posts = try await Post.query(on: req.db).all()
return posts
}
}

在 boot 函数中,我们通过 RoutesBuilder 定义了 route 和 handler 之间的关系。

注册 Controller

现在我们需要将 Controller 注册到 Application 中,让 Application 知道有哪些路由需要被处理

修改 Sources/App/configure.swift

import Fluent
import FluentPostgresDriver
import Vapor
public func configure(_ app: Application) throws {
app.databases.use(.postgres(configuration: SQLPostgresConfiguration(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? SQLPostgresConfiguration.ianaPortNumber,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor_password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database",
tls: .prefer(try .init(configuration: .clientDefault)))
), as: .psql)
app.migrations.add([CreatePost()])
try app.register(collection: PostController())
}

完成添加之后,可以使用 swift run App routes 来打印 App 内生效的 routes

+------+--------+
| GET  | /      |
+------+--------+
| GET  | /posts |
+------+--------+
| POST | /posts |
+------+--------+

测试 PostTests

我们的项目经过了一遍较大的结构改动,但如果逻辑没有错误,我们之前写的 PostTests 应该仍然是可以通过的,换句话说,只要 PostTests 通过了, 我们就无需过于担心功能是否可以正常运行。

运行测试

swift test

测试结果通过

Test Case '-[AppTests.PostTests testCreatePost]' passed (0.230 seconds).

Unit Test 又一次验证了它的必要性。

下章预告

在下一章中,我们将会添加 User 并关联 User 和 Post