I am implementing a delete route handler using Vapor Fluent.
For this handler, I wanted to verify that the user
sending the product deletion request is the owner of the product
, and Abort
the request otherwise.
func deleteHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
let user = req.auth.get(User.self)
return Product.find(req.parameters.get("productID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { product in
return product.$user.get(on: req.db).flatMapThrowing { owner in
guard try user?.requireID() == owner.requireID() else {
throw Abort(.forbidden)
}
return try product.delete(on: req.db)
.transform(to: HTTPStatus.noContent) // error here
}
}
}
But Vapor throws an error at return try product.delete(on: req.db).transform(to: HTTPStatus.noContent)
saying Cannot convert return expression of type 'EventLoopFuture<HTTPResponseStatus>' to return type 'HTTPStatus' (aka 'HTTPResponseStatus')
.
I tried chaining again using map({})
, that did not help. Using wait()
solves the error but introduces a runtime bug.
Thanks for any help!
The problem is that the .flatMapThrowing
isn't throwing the future. requireID()
is overkill in this context. If you replace the throw
as follows and remove the Throwing
as a result, it should work:
func deleteHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
let user = req.auth.get(User.self)
return Product.find(req.parameters.get("productID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { product in
return product.$user.get(on: req.db).flatMap { owner in
guard user?.id == owner.id else {
return request.eventLoop.makeFailedFuture( Abort(.forbidden))
}
return product.delete(on: req.db)
.transform(to: HTTPStatus.noContent)
}
}
}
I've removed the try
from the delete
later on. I'm guessing the compiler didn't report this as unnecessary because of the earlier error, but it isn't usually needed. My answer will fail spectacularly if it is!