as a Function • 2 conceitos principais: Service e Filter Service<Req, Resp> = (Req) -> Future<Resp> • Sistemas representados por funções assíncronas: Filter<ReqIn, RespIn, ReqOut, RespOut> = (ReqIn, Service<ReqOut, RespOut>) -> Future<RespIn> • Preocupações gerais e transformações de I/O:
Usado em produção no Twitter • Scala + Netty • Fintrospect - Camada tipada para Finagle • Boa performance • Sistema de "filtros" • Programação assíncrona estranha • Scala fintrospect.io
(Request) -> Response é apenas uma função: val echo: HttpHandler = { req: Request -> Response(OK).body(req.body) } val resp: Response = echo(Request(POST, “/echo“).body(“hello”))
“Resolve qual HttpHandler pode lidar com uma requisição” val routes: HttpHandler = routes( "/echo" bind POST to echo, "/twitter" bind routes( “/tweet” bind POST to tweet ) ) Routers podem ser combinados e gerar novos HttpHandlers Busca em árvore simples, retorna 404 se não encontrar nada
-> Response usa a mesma função, HttpHandler! val client: HttpHandler = ApacheClient() val response: Response = client( Request(GET, "https://www.http4k.org/search") .query("term", “http4k is cool") )
requisição? • Locais: Path/Query/Header/Body/Form • Mandatoriedade • Conversões + Typesafety • Como criar respostas a partir de tipos bem definidos? val miner: HttpHandler = routes( “/mine/{btc}" bind POST to { r: Request -> val newTotal: Int = r.path("btc")!!.toInt() + 1 val out = “You have $newTotal BTC" val json = """{ "value": "$out"}""" Response(OK).body(json) } )
to focus deeply into a complex structure. They form a combinator library with sensible, general behavior for things like composition, failure, multiplicity, transformation, and representation.” Conceito: Lens
HttpHandler = CatchLensFailure.then( routes( “/mine/{btc}” bind POST to { r: Request -> val newTotal: Int = btcPath.extract(r) + 1 val out = “You have $newTotal BTC" val json = """{ "value": "$out"}""" Response(OK).body(json) } )) • http4k possui Lens para mensagens HTTP. • Violações geram HTTP 400 (Bad Request).
serializar respostas: data class BTC(val value: Int) { operator fun plus(that: BTC) = BTC(value + that.value) fun toString(): value.toString() } class MinedCoin(btc: Btc) { val value = “You have ${btc + BTC(1)} BTC” } val btcPath = Path.int().map(::BTC).of("btc") val jsonBody = Body.auto<MinedCoin>().toLens() val miner: HttpHandler = CatchLensFailure.then( routes( “/mine/{btc}” bind GET to { r: Request -> val mined = MinedCoin(btcPath.extract(r)) jsonBody.inject(mined, Response(OK)) } ))
Launch Application Stack Logging Metrics Remote Clients Application Business Abstraction Business Abstraction As camadas do bolo Route Route Route Route
aplicações e construir um ambiente único em memória • Podemos simular falhas em qualquer parte do sistema, injetando um novo Fake que produz erros particulares. • Todas as aplicações internas e externas são HttpHandlers