Typed Services Using Finch - YOW! Conferences &...

63
TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016

Transcript of Typed Services Using Finch - YOW! Conferences &...

Page 1: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

TYPED SERVICES USING FINCHTom Adams, @tomjadams

LambdaJam 2016

Page 2: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

1SERVICES

Page 3: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

SERVICE• We care about things like

• HTTP primitives• Request/response

encode/decode• Transport protocols• Talking to downstream

services• Local data storage

• But not these• Asset packaging

• View rendering• JavaScript, SASS,

LESS, etc.

Page 4: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

LANDSCAPE

• Go: gokit, Kite

• Elixir: Phoenix

• Javascript: Node.js (TypeScript)

• Clojure: Caribou, Liberator, Rook

• Ruby: Rails, Sinatra, Grape, Lotus

• Erlang: Leptus, Yaws

• Haskell: Snap, rest, servant, Hapstack, Yesod

• Java: Play, Spring, Jersey, Spark, RESTEasy, (Dropwizard)

• Swift: Swifton, Vapor

Page 5: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WHAT’S IN A HTTP FRAMEWORK?

Page 6: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WE NEED

1. Routing

• path/headers/methods/etc. to a function

2. Req → Resp

Page 7: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

SERVICE PRIMITIVES

• Routing is a function

• r :: URI → a

• An “action” is a function

• a :: Req → Resp

• A “controller” is (scoped) a collection of actions

• c :: List a

• A “service” is a collection of controllers

• s :: List c

Page 8: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

BUT WAIT, THERE’S MORE

• HTTP primitives

• Datastore• Metrics• Logging• JSON codec• Databinding• Configuration• Environments

• HTTP clients• Failure

isolation• Async

primitives• Monitoring• Service

discovery

• Debugging/tracing

• Caching• Messaging• Deployment• Testing• Live code

reload• …

Page 9: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

2SCALALet’s talk about Scala

https://github.com/OlegIlyenko/scala-icon

Page 10: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WHY SCALA?• JVM support - “Better Java”

• Fast, scalable

• Deployment & runtime behaviour well understood

• Library & tool support (distributed heap, debugging, etc.)

• Decent (not great) static type system

• Succinct - closures, type classes, type aliases, type inference, no semi-colons

• Features - immutability, equational reasoning, functions, case classes, implicits, packages, mixins, currying/partial application, etc.

• Standard library - option, either, future, etc.

• Cool stuff! scalaz, actors, higher-kinds, etc.

Page 11: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WELL USED• Twitter, Pinterest, Airbnb, SoundCloud, Uber, Strava,

Gilt, LinkedIn, Amazon, Tumblr, Foursquare, Box, Gigya, Simple, Localytics, LivingSocial, eHarmony, Yammer, Firebase, Disqus, Asana, Hootsuite, PagerDuty, Rdio

• Apple, Novell, The Guardian, Sony, BSkyB, AOL, Xerox, Siemens, VMware

• REA, Seek, Skedulo, CBA, Atlassian, Fairfax, RedBalloon, Canva*, Oomph*

Source: Quora, AngelList, scala-lang.org, reddit, LinkedIn, Finagle Adopters

Page 12: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WHY FP?

• (Static) Types, and

• Immutability, and

• Composition, gives rise to

• Equational reasoning, and

• Certainty, and

• Reliability

Page 13: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FRAMEWORK OPTIONS

• Karyon (Netflix)

• Play (Typesafe/Lightbend)

• Unfiltered (OSS)

• Dropwizard (Yammer)

• Spray (Typesafe/Lightbend)

• Finagle (Twitter) / Finatra (OSS) / Finch (OSS)

• Akka, Lagom (Typesafe/Lightbend)

• Colossus (Tumblr)

• Chaos (Mesosphere)

Page 14: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

PERFORMANCE

Page 15: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

3FINCH

Page 16: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FINCH

Finch is a thin layer of purely functional basic blocks on top of Finagle for building HTTP APIs.

It provides developers with simple and robust HTTP primitives, while being as close as possible to the bare metal Finagle API.

Page 17: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

HELLO, WORLD

val service = new Service[Request, Response] { def apply(req: Request) { request.path match { case "/hello" => val resp: Response = Response() resp.content = Buf.Utf8("Hello, World!") Future.value(resp) case _ => Future.value(Response()) }}

Http.server.serve(":8080", service)

Page 18: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

HELLO, WORLD

import io.finch._import com.twitter.finagle.Http

val api: Endpoint[String] = get("hello") { Ok("Hello, World!") }

Http.server.serve(“:8080", api.toService)

Page 19: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

HELLO, WORLD

import io.finch._import com.twitter.finagle.Http

val api: Endpoint[String] = get("hello") { Ok("Hello, World!") }

Http.server.serve(“:8080", api.toService)

Finch

Finagle

Page 20: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FINCH FEATURES

• High level abstraction on top of Finagle (don’t need to drop down to Finagle*)

• Small footprint

• Flexible use (what you make of it)

• Referentially transparent & compositional

• Request / response decoding / encoding

• Explicit async modelling

Page 21: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FINAGLE

A fault tolerant, protocol-agnostic, extensible RPC system for the JVM, used to construct high-concurrency servers.

Finagle implements uniform client and server APIs for several protocols, and is designed for high performance and concurrency.

Page 22: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FINAGLE FEATURES• Connection pools (w/

throttling)• Failure detection• Failover strategies• Load-balancers• Back-pressure• Statistics, logs, and

exception reports• Distributed tracing

(Zipkin)

• Service discovery (ZooKeeper)

• Sharding strategies• Config

Page 23: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

TWITTERSERVER

• Lightweight server template • Command line args• HTTP admin server• Logging• Tracing• Metrics• System stats

Page 24: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WHAT DOES THAT MEAN FOR

• Performance & scalability out of the box

• Maturity of a battle tested framework

• Fast ramp up

• Won’t bottom out as you scale

• Known deployment, monitoring, runtime, etc.

Page 25: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

4CORE FINCH CONCEPTS

Page 26: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

TRIUMVIRATE

• Endpoint

• Filters

• Futures

• (Services)

Page 27: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

ENDPOINT

• A function that takes a request & returns a value

• Automatically handles Future/async

• Provides routing behaviour

• Extracts/matches values from the request

• Values are serialised to the HTTP response

• Composable (applicative)

Page 28: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

EXAMPLE

val divOrFail: Endpoint[Int] = post("div" :: int :: int) { (a: Int, b: Int) => if (b == 0) BadRequest(new ArithmeticException("...")) else Ok(a / b) }

Page 29: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FILTER (FINAGLE)

• Many common behaviours are service agnostic

• Cross cutting concerns

• Timeouts, logging, retries, stats, authentication, etc.

• Filters are composed over services

• Alter the behaviour of a service without caring what it is

Page 30: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FILTER EXAMPLE

val timeout: Filter[...]val auth: Filter[...]val service: Service[Req, Resp]

val composed = timeout andThen auth andThen service

Page 31: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FILTERS ARE FUNCTIONS

type Filter[...] = (ReqIn, Service[ReqOut, RespIn]) => Future[RespOut]

Page 32: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FILTERS ARE TYPESAFE

// A service that requires an authenticated requestval service: Service[AuthReq, Resp]

// Bridge with a filterval auth: Filter[HttpReq, HttpResp, AuthHttpReq, HttpResp]

// Authenticate, and serveval authService: Service[HttpReq, HttpResp] = auth andThen service

Page 33: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FUTURE

• A placeholder for a value that may not yet exist

• Long computations, network calls, disk reads, etc.

• The value is supplied concurrently (executed on thread pool)

• Like callbacks, but not shit

• Oh, and composable (monadic)

Page 34: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

CALLBACK FUTURES

val f: Future[String]

f onSuccess { s => log.info(s)} onFailure { ex => log.error(ex)}

Page 35: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

STATES OF A FUTURE

• 3 states; empty, complete or failed

• “Taints” the types of calling code

• Easy to program against & make async explicit

• Forces handling of async behaviour

• Can also be blocked (if required)

Page 36: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FUTURE IN PRACTICE

val dbUser = facebook.authenticate(token).flatMap { fbUser => val query = findByEmail(fbUser.email).result database.run(query).flatMap(_.headOption)}dbUser.transform { case Return(user) => success(user) case Throw(e) => handleError(e)}

Page 37: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

SERVICE (FINAGLE)

• System boundaries are represented by asynchronous functions called services

• Symmetric and uniform API represents both clients and servers

• You never (usually) write a Finagle service, Finch does that for you

• Services are monadic (you’ll see this a lot…)

Page 38: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

SERVICES ARE FUNCTIONS

type Service[Req, Resp] = Req => Future[Resp]

Page 39: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

SERVICES IN FINCH

object LiegeApi extends ErrorOps with ResponseEncoders { private def api = usersApi() :+: ridesApi()

def apiService: Service[Request, Response] = { val service = api.handle(errorHandler).toService RequestLoggingFilter.andThen(service) }}

Page 40: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

5OTHER GOOD BITS

Page 41: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

DATABINDINGGiven a model

val ts: RequestReader[Token] = (param("t") :: param("a")).as[Token]val ts: RequestReader[Token] = RequestReader.derive[Token].fromParams

case class Token(token: String, algorithm: String)

Create a reader to parse the querystring

val getToken: Endpoint[Token] = get("tokens" ? ts) { (t: Token) => ... }

Automatically parse the querystring in an endpoint

Page 42: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

DATABINDING

Given a model

case class Token(token: String, algorithm: String)

{ "token": "CAAX...kfR", "algorithm": "sha1"}

post("sign-in" ? body.as[Token]) { (t: Token) => ... }

And incoming JSON from a POST request

We can bind as

Page 43: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

“CONTROLLER”object RidesApi extends HttpOps with Logging { def ridesApi() = list :+: details

def list: Endpoint[List[Attendance]] = get("rides" ? authorise) { u: AuthenticatedUser => ... }

def details: Endpoint[Attendance] = get("rides" / string("type") / string("id") ? authorise) { (backend: String, rideId: Id, u: AuthenticatedUser) => ... }}

Page 44: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

class ItemsApiController extends Controller { val itemsService = ... val itemReader = body.as[Item]

def findItemById(itemId: Long): Action = securedAction { reqContext => itemsService.findItemById(itemId) }

def userItems: Action = securedAction(pageReader) { page => implicit reqContext =>

itemsService.userItems(user.id.get, PageRequest(page)) } override def routes: Endpoint[HttpRequest, HttpResponse] = { (Get / "api" / "items" /> userItems) | (Get / "api" / "items" / long /> findItemById) | (Post / "api" / "items" /> newItem) | }}

Page 45: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

import io.finch._import ru.arkoit.finchrich.controller._

object MyAwesomeController extends Controller { val healthcheck = get("healthcheck") { Ok() }

val greeter = get("greet" / param("name")) { n: String => Ok(s"Hello, $n!") }}

val ep = controllerToEndpoint(MyAwesomeController)

Source: https://github.com/akozhemiakin/finchrich

Page 46: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

METRICS

val stats = Stats(statsReceiver)val server = Http.server.configured(stats).serve(":8081", api)

val rides: Counter = statsReceiver.counter("rides")rides.incr()

val ridesLatency: Stat = statsReceiver.stat("rides_latency")Stat.time(ridesLatency) { rides(u).map(rs => Ok(rs.map(r => Attendance(u, r)))) }

Page 47: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

HTTP CLIENTS

val client = Http.client.newService("twitter.com:8081,twitter.com:8082")

val f: Future[HttpRep] = client(HttpReq("/"))

val result: Future[String] = f.map { resp => handleResponse(resp) }

Page 48: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

TESTING

service(HttpReq("/")) map { resp => doStuff(resp) }

Page 49: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

6GETTING STARTED

Page 50: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

WHEN SHOULD I USE IT?

• Complex long / lived system / many developers

• Scale or performance requirements

• Integration with downstream services

• Need to run on the JVM

Page 51: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FINCH

• Watch the Finch videos

• https://skillsmatter.com/skillscasts/6876-finch-your-rest-api-as-a-monad

• Examples

• https://github.com/finagle/finch/tree/master/examples/src/main/scala/io/finch

• Best practices

• https://github.com/finagle/finch/blob/master/docs/best-practices.md

Page 52: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

READ UP ON FINAGLE

• Finagle Users Guide

• Your function as a server (original Finagle paper)

• The anatomy of a twitter microservice

• Fault tolerant clients with Finagle

Page 53: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.
Page 54: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

54

QUESTIONS?

Page 55: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

7YOW WEST SLIDES

Page 56: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

DDL

final case class User(id: Option[Int] = None, name: String, email: String, location: Option[String], avatarUrl: String)

final class UserOps(tag: Tag) extends Table[User](tag, "users") { def id = column[Int]("id", O.PrimaryKey, O.AutoInc) def name = column[String]("name") def email = column[String]("email") def location = column[String]("location")

def * = (id.?, name, email, location.?) <>(User.tupled, User.unapply)

def nameIdx = index("name_idx", name, unique = true)}

Page 57: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

DB ACCESS

object UserOps extends TableQuery(new UserOps(_)) { val findByName = this.findBy(_.name) val findByEmail = this.findBy(_.email)

def insert(u: User) = UserOps += u

def userForToken(token: UserAccessToken): Future[Option[AuthenticatedUser]] = database.run(find(token).result).map(_.headOption.flatMap(asAuthenticatedUser))

def deauthenticateUser(token: AuthToken): Future[Unit] = { val q = for {u <- UserOps if u.authToken === token.asSessionId} yield u.authToken database.run(q.update(null)).flatMap(_ => Future.Done) }}

Page 58: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

MIGRATIONS

object Database { lazy val migrationDatabase = new MigrationDatabase { def migrate(): Unit = { val flyway = new Flyway() flyway.setDataSource(env.dbUrl, env.dbUsername, env.dbPassword) flyway.migrate() } }}

Page 59: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

FUTURE COMBINATORS

• Composed via map, flatMap, handle, transform and rescue

• Exception handling via

• onSuccess(f: A => Unit)

• onFailure(ex: Throwable => Unit)

Page 60: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

IDEAS

• More on request reader stuff, auth, etc.

• Using circle’s auto-derivation

• Abstracting/mapping Twitter Futures from/between Scala Futures from Scalaz Tasks

Page 61: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

IDEAS

• Issues, these may be ok for you

• Twitter stack

• Everything is async, “sensitive to blocking code”, “reactive” bandwagon

• Stuck to netty3

• Documentation not exhaustive, need to rely on Gitter

• Finagle hard to use other metrics

Page 62: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

PROBLEMS WITH FUTURES

• Futures are harder to compose than they need to be

• Try clouds the issue

• respond vs transform

• respond for purely side-effecting callbacks.

• map & flatMap for dealing strictly with successful computations (implemented using transform)

• handle and rescue for dealing strictly with exceptional computations.

Page 63: Typed Services Using Finch - YOW! Conferences & …yowconference.com.au/slides/yowlambdajam2016/Adams... · TYPED SERVICES USING FINCH Tom Adams, @tomjadams LambdaJam 2016. 1 SERVICES.

IDEAS

• Other data layers

• Quill, finagle-mysql