I have the following section of code in a controller, which queries MailGun to send an email, and then should ideally wait for a response before returning in the controller. As configured right now, this should fail as I have intentionally broken my MailGun configuration. But currently the controller is returning a success status, because the .catchMap
functionality is not being properly awaited, and I'm not sure how to correctly structure my code so that it is.
return emailTemplate.render(emailData, on: req).map { message -> Future<Response> in
let deliveryService = try req.make(EmailDeliveryService.self)
return try deliveryService.send(message, on: req)
}.catchMap { error in
/// this is not being awaited, and no abort is thrown before the request returns
throw Abort(.internalServerError, reason: "Error sending email.")
}.transform(to: savedObj)
The function that should be properly awaited, deliverService.send
, has the method signature:
func send(_ message: EmailMessage, on container: Container) throws -> Future<Response>
How can I appropriately structure this code to correctly catch an error that is returned by the result of the deliveryService.send
method?
If your render()
method signature is something like this:
func render(…) -> Future<String>
then, I think you need to use flatMap
instead of map
in:
return emailTemplate.render(emailData, on: req).map // <—
Right now, the catchMap
and transform
method are receiving a Future<Future<Response>>
because map
only transform the encapsulated data of the given future which go like this:
Future<String> -map(String -> Future<Response)-> Future<Future<Response>>
Using flatMap
, it will flatten the double Future, which is the purpose of this method which lead to:
Future<String> -flatMap(String -> Future<Response)-> Future<Response>
Then, the catchMap
will be able to access the error.