|
import akka.actor.ActorSystem |
|
import akka.http.scaladsl.Http |
|
import akka.http.scaladsl.model.{HttpMethods, HttpRequest, StatusCodes, Uri} |
|
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshal} |
|
import akka.stream.ActorMaterializer |
|
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport |
|
|
|
import scala.concurrent.{ExecutionContext, Future} |
|
import scala.util.{Failure, Success} |
|
|
|
object UserService { |
|
|
|
case class User(id: Long, name: String, firstName: String, lastName: String, location: Location) |
|
|
|
case class Location(country: String, city: String) |
|
|
|
} |
|
|
|
trait UserServiceJsonSupport extends FailFastCirceSupport { |
|
|
|
import UserService._ |
|
import io.circe.Decoder |
|
|
|
// enable automatic decoder derivation |
|
import io.circe.generic.auto._ |
|
|
|
/** |
|
* ``` |
|
* { |
|
* "user": { |
|
* "id": 1, |
|
* "name": "okapies", |
|
* "first_name": "Yuta", |
|
* "last_name": "Okamoto", |
|
* "location": { |
|
* "country": "Japan", |
|
* "city": "Tokyo" |
|
* } |
|
* } |
|
* } |
|
* ``` |
|
*/ |
|
implicit val tokenInfoDecoder: Decoder[User] = |
|
Decoder.forProduct5("id", "name", "first_name", "last_name", "location")(User).prepare(_.downField("user")) |
|
// Note: The decoder for Location will be automatically derived by circe. |
|
|
|
} |
|
|
|
class UserServiceClient(val endpoint: Uri) |
|
(implicit val system: ActorSystem, |
|
val materializer: ActorMaterializer, |
|
val executionContext: ExecutionContext) extends UserServiceJsonSupport { |
|
|
|
import UserService._ |
|
|
|
def getUser(username: String): Future[User] = |
|
doRequest[User](HttpRequest(uri = Uri.parseAndResolve(s"/api/v1/users/$username", base = endpoint))) |
|
|
|
private[this] def doRequest[A: FromEntityUnmarshaller](request: HttpRequest): Future[A] = |
|
Http().singleRequest(request).transformWith { |
|
case Success(res) if res.status == StatusCodes.OK => |
|
Unmarshal(res.entity).to[A] |
|
case Success(res) => |
|
res.discardEntityBytes() |
|
Future.failed(new Exception(s"HttpRequest failed: $res")) |
|
case Failure(t) => |
|
Future.failed(t) |
|
} |
|
|
|
} |