Прикованные фьючерсы на SwiftNIO и Vapor
В Vapor 4 я обрабатываю почтовый запрос, вызывая запрос к стороннему API и возвращая значение на основе полученного результата. Следующий код приводит к ошибке: "Недопустимое преобразование из бросающей функции... в не вызывающую функцию"
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")
}
}
Я не могу использовать try
в моих цепях map()
после получения результата API. Приведенный выше код будет работать, если я добавлю!
к try
в let response = try response.content.decode(ResponseModel.self)
внутри карты, но в идеале я хочу поймать эту ошибку. Первыйtry
используется при создании тела ответа, кажется, неявно передается обратно по цепочке, но не вторым.
Что я делаю неправильно? Как отловить ошибку при декодировании содержимого ответа? Почему первыйtry
поймал но не второй?
2 ответа
Собственность map
заключается в том, что он просто преобразует значение на "пути успеха". Однако ваша трансформация может потерпеть неудачу, что означает, что вы, вероятно, тоже хотите, чтобы будущее тоже потерпело неудачу.
Всякий раз, когда вы хотите преобразовать значение с помощью функции, которая либо успешна, либо не работает, вам нужно использовать один из flatMap*
функции.
В вашем случае попробуйте заменить map
с flatMapThrowing
и тогда он должен работать.
Чтобы расширить ответ Йоханнеса Вайса, чтобы иметь метательное закрытие, которое возвращает будущее, вам нужно что-то вроде:
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()
}