From 1ecaf78e466aa6df37379d5202c3f907aefd3775 Mon Sep 17 00:00:00 2001 From: Kseniya Tomskikh Date: Thu, 1 Mar 2018 18:24:01 +0700 Subject: TRIAL-287 Created ListResponse class and directive for pagination parsing --- src/main/scala/xyz/driver/core/rest/package.scala | 44 +++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/scala/xyz/driver/core/rest/package.scala b/src/main/scala/xyz/driver/core/rest/package.scala index 5fd9417..78d04f4 100644 --- a/src/main/scala/xyz/driver/core/rest/package.scala +++ b/src/main/scala/xyz/driver/core/rest/package.scala @@ -14,7 +14,7 @@ import akka.util.ByteString import xyz.driver.tracing.TracingDirectives import scala.concurrent.Future -import scala.util.Try +import scala.util.{Failure, Success, Try} import scalaz.{Functor, OptionT} import scalaz.Scalaz.{intInstance, stringInstance} import scalaz.syntax.equal._ @@ -36,10 +36,39 @@ trait ServiceTransport { object Pagination { val Default = Pagination(pageSize = 100, pageNumber = 1) + + def parse(query: Seq[(String, String)]): Try[Pagination] = { + val IntString = """(\d+)""".r + def validate(field: String, default: Int) = query.collectFirst { case (`field`, size) => size } match { + case Some(IntString(x)) if x.toInt > 0 => x.toInt + case Some(IntString(x)) => throw new Exception(s"$field must greater than zero (found $x)") + case Some(str) => throw new Exception(s"$field must be an integer (found $str)") + case None => default + } + + Try { + Pagination( + validate("pageSize", Pagination.Default.pageSize), + validate("pageNumber", Pagination.Default.pageNumber)) + } + } } final case class Pagination(pageSize: Int, pageNumber: Int) { - def offset: Int = pageSize * pageNumber + def offset: Int = pageSize * (pageNumber - 1) +} + +final case class ListResponse[+T](items: Seq[T], meta: ListResponse.Meta) + +object ListResponse { + + final case class Meta(itemsCount: Int, pageNumber: Int, pageSize: Int) + + object Meta { + def apply(itemsCount: Int, pagination: Pagination): Meta = + Meta(itemsCount, pagination.pageNumber, pagination.pageSize) + } + } object `package` { @@ -204,4 +233,15 @@ object `package` { val sanitizeRequestEntity: Directive0 = { mapRequest(request => request.mapEntity(entity => entity.transformDataBytes(Flow.fromFunction(escapeScriptTags)))) } + + val paginated: Directive1[Pagination] = parameterSeq.flatMap { params => + Pagination.parse(params) match { + case Success(pagination) => provide(pagination) + case Failure(ex) => + reject(ValidationRejection("invalid pagination parameter", Some(ex))) + } + } + + def paginationQuery(pagination: Pagination) = + Seq("pageNumber" -> pagination.pageNumber.toString, "pageSize" -> pagination.pageSize.toString) } -- cgit v1.2.3