使用Async-Await在Vapor-Fluent中实现CRUD函数的问题(Swift 5.6)
在Vapor中使用async-await实现CRUD时的Token删除方法错误排查
我正在尝试理解如何在Vapor中创建CRUD函数,发现first()方法返回EventLoopFuture<Token?>,无法作为可选类型解包。
Token.swift代码
import Foundation import Fluent import Vapor final class Token: Model { // 1 static let schema = "tokens" // 2 @ID(key: .id) var id: UUID? // 3 @Field(key: "token") var token: String @Field(key: "debug") var debug: Bool // 4 init() { } init(token: String, debug: Bool) { self.token = token self.debug = debug } }
TokenController.swift代码
import Foundation import Fluent import Vapor struct TokenController { func create(req: Request) async throws -> HTTPStatus { let token = try req.content.decode(Token.self) try await token.create(on: req.db) return .created } func delete(req: Request) async throws -> HTTPStatus { guard let token = req.parameters.get("token") else { return .badRequest } try await Token.query(on: req.db) .filter(\.$token == token) .first() try await delete(req: req.db) return .noContent } } @available(macOS 12, *) extension TokenController: RouteCollection { func boot(routes: RoutesBuilder) throws { let tokens = routes.grouped("token") tokens.post(use: create) tokens.delete(":token", use: delete) } }
遇到的错误
- Initializer for conditional binding must have Optional type, not 'EventLoopFuture<Token?>'
- 尝试按教程方案改写后新增错误:Value of type 'EventLoopFuture<Token?>' has no member 'delete'
我明确使用了async-await,按文档理解底层的EventLoopFuture<>不应直接处理,但实际操作中还是遇到了这些问题,查过文档和教程步骤仍未解决,请问忽略了什么?
问题根源与解决方案
问题1:未正确获取查询结果
你调用Token.query(...).first()后,没有用try await拿到实际的Token?值,直接操作的话拿到的是EventLoopFuture<Token?>对象,自然无法当作可选类型解包。
问题2:错误的删除调用
你写的try await delete(req: req.db)是无效的,这不是删除数据库记录的正确方式,必须通过查询到的Token实例调用delete(on:)方法,或者使用批量删除查询。
修正后的delete方法
func delete(req: Request) async throws -> HTTPStatus { guard let tokenString = req.parameters.get("token") else { return .badRequest } // 用try await获取实际的Token?实例 guard let token = try await Token.query(on: req.db) .filter(\.$token == tokenString) .first() else { // 若Token不存在,返回404更符合REST规范 return .notFound } // 调用实例的delete方法删除记录 try await token.delete(on: req.db) return .noContent }
额外注意点
- 使用
async-await时,所有Fluent的异步方法(返回EventLoopFuture)都必须用try await包裹,才能拿到实际返回值,避免直接操作EventLoopFuture - 当查询结果可能为空时,用
guard let解包可选值,为空时返回404 Not Found比直接返回204 No Content更合理 - 也可以用批量删除的方式简化代码(无需先查询实例):
这种方式会直接删除匹配的记录,不管是否存在,都可以返回try await Token.query(on: req.db) .filter(\.$token == tokenString) .delete()204 No Content
内容的提问来源于stack exchange,提问作者somethingsomethingswift
相关产品推荐
相关产品推荐

