Created
June 14, 2012 02:45
-
-
Save soheilhy/2927765 to your computer and use it in GitHub Desktop.
Routing based on HTTP method in Finagle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.twitter.finagle.http.path._ | |
import com.twitter.finagle.http.service.RoutingService | |
import com.twitter.finagle.http.{Request, Response, RichHttp, Http} | |
import com.twitter.finagle.{Service, SimpleFilter} | |
import org.jboss.netty.handler.codec.http._ | |
import org.jboss.netty.handler.codec.http.HttpResponseStatus._ | |
import org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1 | |
import org.jboss.netty.buffer.ChannelBuffers.copiedBuffer | |
import org.jboss.netty.util.CharsetUtil.UTF_8 | |
import com.twitter.util.Future | |
import java.net.InetSocketAddress | |
import com.twitter.finagle.builder.{Server, ServerBuilder} | |
import com.twitter.finagle.http.Method | |
/** | |
* This example demonstrates a sophisticated HTTP server that handles exceptions | |
* and performs authorization via a shared secret. The exception handling and | |
* authorization code are written as Filters, thus isolating these aspects from | |
* the main service (here called "Respond") for better code organization. | |
*/ | |
object HttpServer { | |
/** | |
* A simple Filter that catches exceptions and converts them to appropriate | |
* HTTP responses. | |
*/ | |
class HandleExceptions extends SimpleFilter[Request, Response] { | |
def apply(request: Request, service: Service[Request, Response]) = { | |
// `handle` asynchronously handles exceptions. | |
service(request) handle { | |
case error => | |
error.printStackTrace() | |
val statusCode = error match { | |
case _: IllegalArgumentException => | |
FORBIDDEN | |
case _ => | |
INTERNAL_SERVER_ERROR | |
} | |
val errorResponse = Response(HTTP_1_1, statusCode) | |
errorResponse.setContent(copiedBuffer(error.getStackTraceString, UTF_8)) | |
errorResponse | |
} | |
} | |
} | |
/** | |
* A simple Filter that checks that the request is valid by inspecting the | |
* "Authorization" header. | |
*/ | |
class Authorize extends SimpleFilter[Request, Response] { | |
def apply(request: Request, continue: Service[Request, Response]) = { | |
if ("open sesame" == request.getHeader("Authorization")) { | |
continue(request) | |
} else { | |
Future.exception(new IllegalArgumentException("You don't know the secret")) | |
} | |
} | |
} | |
object ShowService extends Service[Request, Response] { | |
def apply(request: Request) = { | |
val response = Response() | |
response.setContent(copiedBuffer("show service world", UTF_8)) | |
Future.value(response) | |
} | |
} | |
class SearchService(val i: Int) extends Service[Request, Response] { | |
def apply(request: Request) = { | |
// If you throw an exception here, the filter will catch it. | |
// throw new RuntimeException("s") | |
Future { | |
val response = Response() | |
response.setContent(copiedBuffer("search service world", UTF_8)) | |
response | |
} | |
} | |
} | |
def main(args: Array[String]) { | |
val handleExceptions = new HandleExceptions | |
val routingService = | |
MyRoutingService.byRequest { request => | |
(request.method, Path(request.path)) match { | |
case Method.Get -> Root / "api1" / Integer(userId) => ShowService | |
case Method.Post -> Root / "api2" / Integer(userId) => new SearchService(userId) | |
} | |
} | |
// compose the Filters and Service together: | |
val debuggingService: Service[Request, Response] = | |
handleExceptions andThen routingService | |
val server: Server = ServerBuilder() | |
.codec(RichHttp[Request](Http())) | |
.bindTo(new InetSocketAddress(8080)) | |
.name("httpserver") | |
.build(debuggingService) | |
} | |
} | |
object MyRoutingService { | |
def byRequest[REQUEST](routes: PartialFunction[Request, Service[REQUEST, Response]]) = | |
new RoutingService( | |
new PartialFunction[Request, Service[REQUEST, Response]] { | |
def apply(request: Request) = routes(request) | |
def isDefinedAt(request: Request) = routes.isDefinedAt(request) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment