package com.spr.blog import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server._ import akka.pattern.ask import com.spr.akka.{AkkaConfiguration, RestApi} import scala.concurrent.Future /** * Wrapper API around a [[BlogEntity]] actor. This pattern is similar in spirit to Akka Typed. */ trait BlogService extends AkkaConfiguration { import BlogEntity._ private val blogEntity = actorRefFactory.actorOf(BlogEntity.props) def getPost(id: PostId): Future[MaybePost[PostContent]] = (blogEntity ? GetPost(id)).mapTo[MaybePost[PostContent]] def addPost(content: PostContent): Future[PostAdded] = (blogEntity ? AddPost(content)).mapTo[PostAdded] def updatePost(id: PostId, content: PostContent): Future[MaybePost[PostUpdated]] = (blogEntity ? UpdatePost(id, content)).mapTo[MaybePost[PostUpdated]] } /** * HTTP routes for the BlogService API. */ trait BlogRestApi extends RestApi with BlogService { override def route: Route = pathPrefix("api" / "blog") { (pathEndOrSingleSlash & post) { // POST /api/blog/ entity(as[PostContent]) { content => onSuccess(addPost(content)) { added => complete((StatusCodes.Created, added)) } } } ~ pathPrefix(JavaUUID.map(PostId(_))) { id => pathEndOrSingleSlash { get { // GET /api/blog/:id onSuccess(getPost(id)) { case Right(content) => complete((StatusCodes.OK, content)) case Left(error) => complete((StatusCodes.NotFound, error)) } } ~ put { // PUT /api/blog/:id entity(as[PostContent]) { content => onSuccess(updatePost(id, content)) { case Right(updated) => complete((StatusCodes.OK, updated)) case Left(error) => complete((StatusCodes.NotFound, error)) } } } } } } }