$30 off During Our Annual Pro Sale. View Details »

Two Scoops of Scala

Two Scoops of Scala

April tech talk at FullContact

Kārlis Lauva

April 09, 2014
Tweet

More Decks by Kārlis Lauva

Other Decks in Programming

Transcript

  1. Two scoops of Scala &
    Unfiltered
    April 2014 FullContact techTalk
    @skazhy

    View Slide

  2. Scala?
    ● object oriented and functional programming
    language
    ● Type safe
    ● Runs on JVM

    View Slide

  3. Unfiltered?
    ● A toolkit for HTTP in Scala
    ● Really, really modular
    ● Works with Netty and Jetty
    ● Built for meetup.com realtime API
    ● Makes good use of Scala's idioms

    View Slide

  4. Toolchain
    ● SBT - Scala Build Tool
    ● Best conventions from Maven world
    ● Iterative development in SBT shell

    View Slide

  5. My setup
    ● IntelliJ + SBT console(s) inside tmux
    ● IntelliJ 13 has SBT support baked in

    View Slide

  6. Deployment
    ● Works great with Jenkins & Asgard
    ● Minimal configuration tweaks needed (wait
    for the next slide)

    View Slide

  7. ● A tool for fetching templates for Scala
    projects
    ● g8 skazhy/unfiltered-netty-rx
    ● All SBT plugins for deployment and IntelliJ
    are included
    Bootstrapping with giter8

    View Slide

  8. Using opinionated
    RESTful frameworks for
    microservices?

    View Slide

  9. View Slide

  10. Example time!

    View Slide

  11. object MyPlan extends cycle.Plan with
    cycle.ThreadPool with ServerErrorResponse {
    def intent = {
    case GET(Path("/")) => ResponseString("Hello!")
    case OPTIONS(_) => Created ~> Location("/foo")
    case _ => NotFound
    }
    }
    unfiltered.netty.Http(1337).handler(MyPlan).run()

    View Slide

  12. An Intent is a partial function that pattern
    matches HTTP requests

    View Slide

  13. A Plan is a binding between intent and the
    underlying interface

    View Slide

  14. Pattern matching
    ● Decomposing data structures to extract
    certain fields or validate them
    ● Really powerful in Scala
    ● “routing” mechanism in Unfiltered

    View Slide

  15. View Slide

  16. Match on request methods
    ● Use builtins:
    GET(_)
    POST(_)
    PATCH(_)
    ● Or define your own:
    object SPACEJUMP extends Method("SPACEJUMP")

    View Slide

  17. What happens under the hood?
    class Method(method: String) {
    def unapply[T](req: HttpRequest[T]) =
    if (req.method.equalsIgnoreCase(method)) Some(req)
    else None
    }
    object POST extends Method("POST")

    View Slide

  18. Match on request headers
    BasicAuth(username, password)
    UserAgent("Cobook")

    View Slide

  19. ...on URN
    Path("/foobar")
    Path(Seg("contactLists" :: "v2" :: listId :: Nil))
    // Will extract /contactLists/v2/1234

    View Slide

  20. ...or query parameters
    object AccountIdParam extends
    Params.Extract("numericId", Params.first ~>
    Params.nonempty ~> Params.long)
    PATCH(Params(AccountIdParam(accountId)))
    // Will extract 1234 from PATCH /foo?numericId=1234

    View Slide

  21. View Slide

  22. function composition!

    View Slide

  23. Responses are composable
    case _ =>
    Unauthorized ~>
    ResponseString("No pasaran") ~>
    ResponseHeader("WWW-Authenticate", "Basic realm=foo")

    View Slide

  24. ● HTTP requests are stateless
    ● HTTP responses are side effects

    View Slide

  25. Async made easy
    case req @ GET(Path("/async")) =>
    val futureOp = asyncOperation
    futureOp.onSuccess {
    case result =>
    req.respond(Ok ~> ResponseString(result))
    }
    futureOp.onFailure {
    case _ => req.respond(InternalServerError)
    }

    View Slide

  26. Unfiltered plays well with
    RxJava too

    View Slide

  27. case req @ GET(Path("/reactive")) =>
    observableOp.subscribe(
    result => req.respond(ResponseString(result))
    _ => req.respond(InternalServerError)
    )

    View Slide

  28. What about testing?

    View Slide

  29. ● Separate library for testing with Specs2
    ● Mocking with Mockito
    ● Comes bundled with the giter8 template
    unfiltered-specs2

    View Slide

  30. object OperationPostSpec extends Specification {
    "PATCH /foo" should {
    lazy val r = Http(url((host \ "foo").PATCH))
    lazy val response = r()
    "return HTTP 200" in {
    response.getResponseStatus mustEqual 200
    }
    }
    }

    View Slide

  31. Consider using Unfiltered when you...
    ● need an async & lightweight HTTP service
    ● Have separate business logic
    ● Want to leverage the λ-force

    View Slide

  32. Questions?

    View Slide