Hi folks,
I’m quite new to Scala and am working on an Akka Http REST API that connects to a Postgres database via Slick.
Basically, the routes should ask the categoryRepository actor to request a list of Categories from the CategoriesDao, which uses Slick to query the database.
CategoriesDao and categoryRepository should respond with a Seq[Category] which is then mapped to a List[Category] in the route, which should complete as JSON.
I figure somewhere along the way I am providing an incompatible value, or not handling a Future correctly but the compiler isn’t complaining. The code is compiling but then responding to GET requests with a 500 error.
Does anyone have advice on how I should go about debugging this?
The various parts are:
//CategoryRoutes.scala
import scala.concurrent._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._
import akka.util.Timeout
import akka.pattern.ask
import com.foram.models.{Category, Categories}
import com.foram.actors.CategoryRepository._
import com.foram.Main.{categoryRepository}
import scala.concurrent.duration._
class CategoryRoutes {
import com.foram.JsonFormats._
implicit val timeout = Timeout(2 seconds)
val categoryRoutes =
pathPrefix("api" / "categories") {
get {
path(IntNumber) { id =>
complete((categoryRepository ? GetCategoryByID(id)).mapTo[Option[Category]])
} ~
pathEndOrSingleSlash {
complete((categoryRepository ? GetAllCategories).mapTo[List[Category]])
}
}
}
}
// CategoryRepository.scala
import scala.concurrent.ExecutionContext.Implicits.global
import akka.actor.{Actor, ActorLogging, Props}
import com.foram.dao.CategoriesDao
import com.foram.models.{Category, Categories}
import scala.util.{Failure, Success}
object CategoryRepository {
case class ActionPerformed(action: String)
case object GetAllCategories
case class GetCategoryByID(id: Int)
case class CreateCategory(category: Category)
case class UpdateCategory(id: Int, category: Category)
case class DeleteCategory(id: Int)
case object OperationSuccess
def props = Props[CategoryRepository]
}
class CategoryRepository extends Actor with ActorLogging {
import CategoryRepository._
override def receive: Receive = {
case GetAllCategories =>
println(s"CategoryRepositoryActor Searching for categories")
val allCategories = CategoriesDao.findAll
allCategories.onComplete {
case Success(categories) => sender() ! Categories(categories)
case Failure(failure) => println("Data not found")
}
case GetCategoryByID(id) =>
println(s"Finding category with id: $id")
val category = CategoriesDao.findById(id)
category.onComplete {
case Success(category) => sender() ! category
case Failure(failure) => println(s"$id category not found")
}
case CreateCategory(category) =>
println(s"Creating category $category")
CategoriesDao.create(category)
sender() ! ActionPerformed(s"Category ${category.name} created.")
// TODO
// case UpdateCategory(id, category) =>
// log.info(s"Updating category $category")
// categories = categories + (id -> category)
// sender() ! OperationSuccess
case DeleteCategory(id) =>
println(s"Removing category id $id")
val category = CategoriesDao.delete(id)
category.onComplete {
case Success(category) => sender() ! ActionPerformed(s"Category $id deleted")
case Failure(failure) => println(s"Unable to delete category $id")
}
}
}
// CategoriesDAO.scala
import com.foram.models.Category
import slick.jdbc.PostgresProfile.api._
import scala.concurrent.Future
object CategoriesDao extends BaseDao {
def findAll: Future[Seq[Category]] = db.run(categories.result)
def findById(id: Int): Future[Category] = db.run(categories.filter(_.id === id).result.head)
def create(category: Category) = categories.returning(categories.map(_.id)) += category
def delete(id: Int) = db.run(categories.filter(_.id === id).delete)
}
I would be very grateful for any debugging advice anyone can offer.
The full source code is available in this GitHub repo.
1 post - 1 participant