Skip to content

Instantly share code, notes, and snippets.

trait DefaultResponseSerializerComponent extends ResponseSerializerComponent {
override def responseSerializer: ResponseSerializer = new ResponseSerializer {
override def serialiseResponse[B: Encoder](e: Either[ErrorResponse, B]): Json = e match {
case Left(x) => x.asJson
case Right(x) =>
Json.fromFields(List(
("status", Json.fromString("200")),
("data", x.asJson)
))
}
trait DefaultExceptionHandler extends ExceptionHandlerComponent {
private val l = Logger(classOf[DefaultExceptionHandler])
override def exceptionHandler: ExceptionHandler = new ExceptionHandler {
override def handle[B](e: ApiResponse[B]): Either[ErrorResponse, B] = e match {
case Left(x: JsonError) => errorResponse("400", s"Error de-serialising JSON: ${x.getMessage}")
case Left(x: NotFound) => errorResponse("404", x.message)
case Left(x: BadRequest) => errorResponse("400", x.message)
case Left(x: InternalServerError) => errorResponse("500", x.message)
case Left(x) => errorResponse("500", x.getMessage)
case Right(x) => Right(x)
object ApiResponse {
def failure[T](e :Exception): ApiResponse[T] = Left(e)
def success[T](t: T): ApiResponse[T] = Right(t)
}
class TestFunction extends Controller[TestInput, TestOutput]
with DefaultResponseSerializerComponent
with DefaultExceptionHandler {
override def handleRequest(in: TestInput): ApiResponse[TestOutput] =
success(TestOutput(s"OUTPUT:${in.value}"))
}
repositories {
maven {
url "https://dl.bintray.com/robhinds/snapshots"
}
}
dependencies {
compile 'io.github.robhinds:ScaLambda:0.0.1'
}
case class TestInput(value: String)
case class TestOutput(value: String)
trait MethodAndPathDirectives {
def getPath[L](x: PathMatcher[L]): Directive[L] = get & path(x)
def postPath[L](x: PathMatcher[L]): Directive[L] = post & path(x)
def putPath[L](x: PathMatcher[L]): Directive[L] = put & path(x)
def deletePath[L](x: PathMatcher[L]): Directive[L] = delete & path(x)
def headPath[L](x: PathMatcher[L]): Directive[L] = head & path(x)
}
trait ResponseHandler {
this: ResponseWrapperEncoder =>
import io.circe.syntax._
import io.circe.generic.auto._
def respond[A](response: Future[Response[A]], successStatusCode: StatusCode = StatusCodes.OK)
(implicit ee: Encoder[AkkOpError], te: Encoder[A]): StandardRoute = {
complete(responseTuple(response))
}
type Response[T] = Either[AkkOpError, T]
object Errors {
sealed trait AkkOpError {
val statusCode: Int
val data: String
}
case class NotFound(data: String, statusCode: Int = StatusCodes.NotFound.intValue) extends AkkOpError
class UserRoutes {
this: UserServiceComponent =>
val routes: Route =
getPath("users" / JavaUUID) { uuid =>
respond(userService.getUser(GetUserRequest(None, Some(uuid))))
} ~
getPath("users" / Segment) { handle =>
respond(userService.getUser(GetUserRequest(Some(handle), None)))
}