SwiftNIO 和 Vapor 中的链式投掷期货

Chained Throwing Futures in SwiftNIO & Vapor

在 Vapor 4 中,我正在处理一个 post 请求,方法是调用第 3 方 API 的请求并根据我返回的结果返回一个值。以下代码导致错误:"Invalid conversion from throwing function ... to non-throwing function"

 app.post("activate") { req -> EventLoopFuture<ActivationRequestResponse> in

        return req.client.post("https://api.example.com/activation", headers: HTTPHeaders(), beforeSend: { (req) in
            try req.content.encode(RequestBody(value: someValue), as: .json)
        })

        .map { (response) -> ActivationRequestResponse in

            let response = try response.content.decode(ResponseModel.self)
            return ActivationRequestResponse(success: true, message: "success")

        }

    }

在获得 API 结果后,我似乎无法在链接的 map() 中使用 try。如果我将 ! 添加到地图内 let response = try response.content.decode(ResponseModel.self) 中的 try,上面的代码将起作用,但理想情况下我想捕获此错误。创建响应主体时使用的第一个 try 似乎隐式传递回链,但不是第二个。

我做错了什么?如何在解码响应内容时捕获错误?为什么第一个 try 被抓到而第二个没有被抓到?

map的属性在于,它只是在“成功路径”上转换一个值。然而,你的转型可能会失败,这意味着你可能希望未来也失败。

每当您想使用成功或失败的函数转换值时,您需要使用 flatMap* 函数之一。

对于您的情况,请尝试将 map 替换为 flatMapThrowing,然后它应该会起作用。

要扩展 Johannes Weiss 的答案,要有一个 returns 未来的抛出闭包,您需要类似的东西:

future.flatMap {
    do {
        return try liveDangerously()
    } catch {
        future.eventLoop.makeFailedFuture(error)
    }
}

这样做了很多次之后,我决定自己动手(虽然名字有点可疑):

extension EventLoopFuture {
    @inlinable
    public func flatterMapThrowing<NewValue>(file: StaticString = #file,
            line: UInt = #line,
            _ callback: @escaping (Value) throws -> EventLoopFuture<NewValue>) -> EventLoopFuture<NewValue> {
        return self.flatMap(file: file, line: line) { (value: Value) -> EventLoopFuture<NewValue> in
            do {
                return try callback(value)
            } catch {
                return self.eventLoop.makeFailedFuture(error)
            }
        }
    }
}

这样你就可以写:

future.flatterMapThrowing {
    return try liveDangerously()
}