So I'm trying to call a second endpoint in one of my Vapor endpoints. I have one endpoint that is just a get and works good:
router.get("status") { req -> Future<ConnectionResponse> in
let client = try req.make(Client.self)
let response = client.get("https://url.com/endpoint/")
return response.flatMap(to: ConnectionResponse.self, { response in
return try response.content.decode(ConnectionResponse.self)
})
}
This returns correctly a ConnectionResponse json. When I try to do the same, but in a POST that needs some parameters, I can't figure out why the compiler doesn't let me run:
router.post("purchase") { req -> Future<ConnectionResponse> in
return try req.content.decode(PurchaseRequest.self).map(to: ConnectionResponse.self, { response in
let client = try req.make(Client.self)
let response = client.get("https://url.com/endpoint/")
return response.flatMap(to: ConnectionResponse.self, { response in
return try response.content.decode(ConnectionResponse.self)
})
})
}
It fails on the flatMap
saying Cannot convert return expression of type 'EventLoopFuture<ConnectionResponse>' to return type 'ConnectionResponse'
.
As you can see, the purchase
GET call is the same as the status
apart from the initial decoding of the POST parameters. What am I doing wrong?
Simply replace
return try req.content.decode(PurchaseRequest.self).map(to: ConnectionResponse.self, { response in
with
return try req.content.decode(PurchaseRequest.self).flatMap(to: ConnectionResponse.self, { response in
Complete working code may look like this
router.post("purchase") { req -> Future<ConnectionResponse> in
return try req.content.decode(PurchaseRequest.self).flatMap { response in
let client = try req.make(Client.self)
let response = client.get("https://url.com/endpoint/")
return response.flatMap { response in
return try response.content.decode(ConnectionResponse.self)
}
}
}
So what is the difference between map
and flatMap
?
flatMap
is used if next result is Future<Something>
e.g.:
someDatabaseCall(on: container).flatMap { databaseResult1 in
/// it will return Future<DatabaseResult>
/// that's why we use `flatMap` above instead of `map`
return anotherDatabaseCall(on: container)
}
map
is for non-future results e.g.:
someDatabaseCall(on: container).map { databaseResult1 in
/// it will return non-future result
/// that's we use `map` above instead of `flatMap`
return "hello world" // just simple string
}
What is Future<>
? It's just a promise, like an object with callback.