Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

● 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

Slide 8

Slide 8 text

Using opinionated RESTful frameworks for microservices?

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Example time!

Slide 11

Slide 11 text

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()

Slide 12

Slide 12 text

An Intent is a partial function that pattern matches HTTP requests

Slide 13

Slide 13 text

A Plan is a binding between intent and the underlying interface

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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")

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

...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

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

function composition!

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

● HTTP requests are stateless ● HTTP responses are side effects

Slide 25

Slide 25 text

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) }

Slide 26

Slide 26 text

Unfiltered plays well with RxJava too

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

What about testing?

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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 } } }

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Questions?