All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finatra.http.internal.routing.RoutingService.scala Maven / Gradle / Ivy

package com.twitter.finatra.http.internal.routing

import com.twitter.finagle.Service
import com.twitter.finagle.http.Method._
import com.twitter.finagle.http.Fields
import com.twitter.finagle.http.Method
import com.twitter.finagle.http.Request
import com.twitter.finagle.http.Response
import com.twitter.finagle.http.Status
import com.twitter.finatra.http.exceptions.RouteParamExtractionException
import com.twitter.finatra.http.exceptions.UnsupportedMethodException
import com.twitter.finatra.http.response.SimpleResponse
import com.twitter.util.Future
import com.twitter.util.logging.Logger

private object RoutingService {
  val AllowedMethods: Seq[Method] =
    Seq(Connect, Get, Post, Put, Delete, Options, Patch, Head, Trace)

  val AllowedMethodsStr: String =
    AllowedMethods.map(_.name.toUpperCase).mkString(", ")

  val logger: Logger = Logger(RoutingService.getClass)
}

private[http] class RoutingService(routes: Seq[Route]) extends Service[Request, Response] {

  import RoutingService._

  private[this] val routesToMatch = Routes.createRoutes(routes)
  private[this] val routesStr = routes.map(_.summary).mkString(", ")

  /* Public */

  override def apply(request: Request): Future[Response] = {
    route(request, bypassFilters = false)
  }

  /* Private */

  // optimized
  private[finatra] def route(request: Request, bypassFilters: Boolean): Future[Response] = {
    request.method match {
      case Connect | Get | Post | Put | Delete | Options | Patch | Head | Trace =>
        try {
          routesToMatch
            .handle(request, bypassFilters)
            .getOrElse(notFound(request))
        } catch {
          case _: UnsupportedMethodException =>
            methodNotAllowed(request.method, request.path)
          case e: RouteParamExtractionException =>
            badRequest(e.getMessage)
        }
      case _ =>
        badRequest(request.method.toString + " is not a valid HTTP method")
    }
  }

  private[this] def notFound(request: Request): Future[Response] = {
    logger.debug(request + " not found in registered routes: " + routesStr)
    Future.value(SimpleResponse(Status.NotFound))
  }

  private[this] def badRequest(message: String): Future[Response] = {
    Future.value(SimpleResponse(Status.BadRequest, message))
  }

  private[this] def methodNotAllowed(method: Method, path: String): Future[Response] = {
    val response =
      SimpleResponse(
        Status.MethodNotAllowed,
        s"${method.toString} is not allowed on path $path"
      )
    response.headerMap.set(Fields.Allow, AllowedMethodsStr)
    Future.value(response)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy