SlideShare une entreprise Scribd logo
1  sur  17
Télécharger pour lire hors ligne
Finch.io 
Purely Functional REST API 
with Finagle 
Vladimir Kostyukov 
http://vkostyukov.ru
http://github.com/finagle/finch 
2
Finch.io: Quickstart 
1 def hello(name: String) = new Service[HttpRequest, HttpResponse] = { 
2 def apply(req: HttpRequest) = for { 
3 title <- OptionalParam("title")(req) 
4 } yield Ok(s"Hello, ${title.getOrElse("")} $name!") 
5 } 
6 
7 val endpoint = new Endpoint[HttpRequest, HttpResponse] { 
8 def route = { 
9 // routes requests like '/hello/Bob?title=Mr.' 
10 case Method.Get -> Root / "hello" / name => hello(name) 
11 } 
12 } 
3
Finch.io Overview 
• Composable Endpoints 
• Composable Microservices 
• Request Reader 
• Response Builder 
• JSON 
• OAuth2, Basic Auth 
4
Endpoints 
1 val a = new Endpoint[HttpRequest, HttpResponse] { 
2 def route = { 
3 case Method.Get -> Root / "bob" => Redirect("/users/bob") 
4 case Method.Get -> Root / "users" / Long(id) => GetUser(id) 
5 } 
6 } 
7 
8 val b = new Endpoint[HttpRequest, HttpResponse] { 
9 def route = { 
10 case Method.Get -> Root / "tickets" => GetTickets 
11 } 
12 } 
13 
14 val c: Endpoint[HttpRequest, HttpResponse] = a orElse b 
15 val d: Service[HttpRequest, HttpResponse] = c.toService 
5
Composing services & endpoints 
1 val ab: Filter[A, C, B, C] = ??? 
2 val bc: Endpoint[B, C] = ??? 
3 val cd: Service[C, D] = ??? 
4 
5 val ad: Endpoint[A, D] = ab ! bc ! cd 
6
Case Study: Feedbacks Endpoint 
1 object Feedback extends Endpoint[OAuth2Request[OAuthUser], JsonResponse] { 
2 def route = { 
3 case Method.Get -> Root / "users" / Long(id) / "feedbacks" => 
4 GetUserFeedbacks(id) ! 
5 JoinInnerArrays("attachments") ! 
6 TakeAll 
7 
8 case Method.Put -> Root / "orders" / Long(id) / "feedback" => 
9 ByUserId(MakeSureUserCanPutOrderFeedback(_, id)) ! 
10 MakeSureThereIsNoOrderFeedbacks(id) ! 
11 MakeSureOrderIsCompleted(id) ! 
12 PutOrderFeedback(id) ! 
13 ByLocation(UpdateServiceRating) ! 
14 ByLocation(SendFeedbackSubmittedMail) ! 
15 ByLocation(GetFeedback) ! 
16 TakeFirst 
17 } 
18 } 
7
Params (Reader Monad) 
1 val user = for { 
2 name <- RequiredParam("name") 
3 age <- RequiredIntParam("age") 
4 city <- OptionalParam("city") 
5 } yield User(name, age, city.getOrElse("Novosibirsk")) 
6 
7 val service = new Service[HttpRequest, JsonResponse] { 
8 def apply(req: HttpRequest) = for { 
9 u <- user(req) 
10 } yield JsonObject( 
11 "name" -> u.name, 
12 "age" -> u.age, 
13 "city" -> u.city 
14 ) 
15 } 
16 
17 val u: Future[User] = user(request) handle { 
18 case e: ParamNotFound => BadRequest(e.param) 
19 } 
8
Case Study: Pagination 
1 val pagination = { 
2 val outerLimit = Config[Int]("limit", 15) 
3 
4 for { 
5 offset <- OptionalIntParam("offset") 
6 limit <- OptionalIntParam("limit") 
7 } yield ( 
8 offset.getOrElse(0), 
9 math.min(limit.getOrElse(outerLimit), outerLimit) 
10 ) 
11 } 
12 
13 val a = new Service[HttpRequest, HttpResponse] { 
14 def apply(req: HttpRequest) = for { 
15 (offset, limit) <- pagination(req) 
16 } yield Ok(s"offset $offset, limit $limit") 
17 } 
9
Multi-Value Params 
1 val reader = for { 
2 a <- RequiredIntParams("a") 
3 b <- RequiredIntParams("b") 
4 } yield (a, b) 
5 
6 // request("a=1,2,3&b=4&b=5") 
7 val (a, b): (List[Int], List[Int]) = reader(request) 
8 // a = List(1, 2, 3) 
9 // b = List(4, 5) 
10
Validation 
1 val adult = for { 
2 u <- user 
3 _ <- ValidationRule("age", "should be greater then 18") { user.age >= 18 } 
4 } yield u 
5 
6 val user: Future[User] = adult(request) handle { 
7 case e: ParamNotFound => 
8 BadRequest(JsonObject("param" -> e.param)) 
9 case e: ValidationFailed => 
10 BadRequest(JsonObject("param" -> e.param, "rule" -> e.rule)) 
11 } 
11
Responses 
1 // an empty response with status 200 
2 val a = Ok() 
3 
4 // 'plain/text' response with status 404 
5 val b = NotFound("body") 
6 
7 // 'application/json' response with status 201 
8 val c = Created(JsonObject("id" -> 42)) 
9 
10 // 'plain/text' response of status 403 with custom header 
11 val d = Forbidden.withHeaders("Some-Header-A" -> "a")("plain") 
12
JSON 
1 // a : { 
2 // b : 10, 
3 // c : 20, 
4 // d : 30 
5 // } 
6 val a = JsonObject("a.b" -> 10, "a.c" -> 20, "a.d" -> 30) 
7 
8 // a : { 
9 // a : 100, 
10 // b : 200 
11 // } 
12 val b = JsonObject("a.a" -> 100, "a.b" -> 200) 
13 
14 // a : { 
15 // a : 100 
16 // b : 200, 
17 // c : 20, 
18 // d : 30 
19 // } 
20 val c = JsonObject.mergeRight(a, b) 
13
Basic Auth 
1 object ProtectedUser extends Endpoint[HttpRequest, HttpResponse] { 
2 def route = { 
3 case Method.Get -> Root / "users" => 
4 BasicallyAuthorize("user", "password") ! 
5 GetUsers 
6 } 
7 } 
14
Further Steps 
• Lightweight in-memory caching 
• Better JSON 
15
References 
§ http://twitter.github.io/finagle/ 
! 
§ https://github.com/finagle/finch 
! 
§ https://github.com/finagle/finagle-oauth2 
16
Stay Finagled! 
! 
And drop your feedbacks to 
@vkostyukov 
17

Contenu connexe

Tendances

Asynchronous I/O in PHP
Asynchronous I/O in PHPAsynchronous I/O in PHP
Asynchronous I/O in PHP
Thomas Weinert
 
Decoupling Objects With Standard Interfaces
Decoupling Objects With Standard InterfacesDecoupling Objects With Standard Interfaces
Decoupling Objects With Standard Interfaces
Thomas Weinert
 

Tendances (20)

Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & Collections
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
React for Beginners
React for BeginnersReact for Beginners
React for Beginners
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance Issues
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
 
Talk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe ConversetTalk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe Converset
 
Python meetup: coroutines, event loops, and non-blocking I/O
Python meetup: coroutines, event loops, and non-blocking I/OPython meetup: coroutines, event loops, and non-blocking I/O
Python meetup: coroutines, event loops, and non-blocking I/O
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 
Flamingo Training - Hello World
Flamingo Training - Hello WorldFlamingo Training - Hello World
Flamingo Training - Hello World
 
PyCon lightning talk on my Toro module for Tornado
PyCon lightning talk on my Toro module for TornadoPyCon lightning talk on my Toro module for Tornado
PyCon lightning talk on my Toro module for Tornado
 
Asynchronous I/O in PHP
Asynchronous I/O in PHPAsynchronous I/O in PHP
Asynchronous I/O in PHP
 
第4回 g* ワークショップ はじめてみよう! Grailsプラグイン
第4回 g* ワークショップ はじめてみよう! Grailsプラグイン第4回 g* ワークショップ はじめてみよう! Grailsプラグイン
第4回 g* ワークショップ はじめてみよう! Grailsプラグイン
 
2016 gunma.web games-and-asm.js
2016 gunma.web games-and-asm.js2016 gunma.web games-and-asm.js
2016 gunma.web games-and-asm.js
 
20151224-games
20151224-games20151224-games
20151224-games
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaIntroduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoa
 
Decoupling Objects With Standard Interfaces
Decoupling Objects With Standard InterfacesDecoupling Objects With Standard Interfaces
Decoupling Objects With Standard Interfaces
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0
 
Using Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasetsUsing Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasets
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 

Similaire à Finch.io - Purely Functional REST API with Finagle

CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
stasimus
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
Ismael Celis
 

Similaire à Finch.io - Purely Functional REST API with Finagle (20)

Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
RESTful API 제대로 만들기
RESTful API 제대로 만들기RESTful API 제대로 만들기
RESTful API 제대로 만들기
 
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Top 10 F5 iRules to migrate to a modern load balancing platform
Top 10 F5 iRules to migrate to a modern load balancing platformTop 10 F5 iRules to migrate to a modern load balancing platform
Top 10 F5 iRules to migrate to a modern load balancing platform
 
Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
Rpi python web
Rpi python webRpi python web
Rpi python web
 
Intro to Sail.js
Intro to Sail.jsIntro to Sail.js
Intro to Sail.js
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
Ajax - a quick introduction
Ajax - a quick introductionAjax - a quick introduction
Ajax - a quick introduction
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Dernier (20)

MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Finch.io - Purely Functional REST API with Finagle

  • 1. Finch.io Purely Functional REST API with Finagle Vladimir Kostyukov http://vkostyukov.ru
  • 3. Finch.io: Quickstart 1 def hello(name: String) = new Service[HttpRequest, HttpResponse] = { 2 def apply(req: HttpRequest) = for { 3 title <- OptionalParam("title")(req) 4 } yield Ok(s"Hello, ${title.getOrElse("")} $name!") 5 } 6 7 val endpoint = new Endpoint[HttpRequest, HttpResponse] { 8 def route = { 9 // routes requests like '/hello/Bob?title=Mr.' 10 case Method.Get -> Root / "hello" / name => hello(name) 11 } 12 } 3
  • 4. Finch.io Overview • Composable Endpoints • Composable Microservices • Request Reader • Response Builder • JSON • OAuth2, Basic Auth 4
  • 5. Endpoints 1 val a = new Endpoint[HttpRequest, HttpResponse] { 2 def route = { 3 case Method.Get -> Root / "bob" => Redirect("/users/bob") 4 case Method.Get -> Root / "users" / Long(id) => GetUser(id) 5 } 6 } 7 8 val b = new Endpoint[HttpRequest, HttpResponse] { 9 def route = { 10 case Method.Get -> Root / "tickets" => GetTickets 11 } 12 } 13 14 val c: Endpoint[HttpRequest, HttpResponse] = a orElse b 15 val d: Service[HttpRequest, HttpResponse] = c.toService 5
  • 6. Composing services & endpoints 1 val ab: Filter[A, C, B, C] = ??? 2 val bc: Endpoint[B, C] = ??? 3 val cd: Service[C, D] = ??? 4 5 val ad: Endpoint[A, D] = ab ! bc ! cd 6
  • 7. Case Study: Feedbacks Endpoint 1 object Feedback extends Endpoint[OAuth2Request[OAuthUser], JsonResponse] { 2 def route = { 3 case Method.Get -> Root / "users" / Long(id) / "feedbacks" => 4 GetUserFeedbacks(id) ! 5 JoinInnerArrays("attachments") ! 6 TakeAll 7 8 case Method.Put -> Root / "orders" / Long(id) / "feedback" => 9 ByUserId(MakeSureUserCanPutOrderFeedback(_, id)) ! 10 MakeSureThereIsNoOrderFeedbacks(id) ! 11 MakeSureOrderIsCompleted(id) ! 12 PutOrderFeedback(id) ! 13 ByLocation(UpdateServiceRating) ! 14 ByLocation(SendFeedbackSubmittedMail) ! 15 ByLocation(GetFeedback) ! 16 TakeFirst 17 } 18 } 7
  • 8. Params (Reader Monad) 1 val user = for { 2 name <- RequiredParam("name") 3 age <- RequiredIntParam("age") 4 city <- OptionalParam("city") 5 } yield User(name, age, city.getOrElse("Novosibirsk")) 6 7 val service = new Service[HttpRequest, JsonResponse] { 8 def apply(req: HttpRequest) = for { 9 u <- user(req) 10 } yield JsonObject( 11 "name" -> u.name, 12 "age" -> u.age, 13 "city" -> u.city 14 ) 15 } 16 17 val u: Future[User] = user(request) handle { 18 case e: ParamNotFound => BadRequest(e.param) 19 } 8
  • 9. Case Study: Pagination 1 val pagination = { 2 val outerLimit = Config[Int]("limit", 15) 3 4 for { 5 offset <- OptionalIntParam("offset") 6 limit <- OptionalIntParam("limit") 7 } yield ( 8 offset.getOrElse(0), 9 math.min(limit.getOrElse(outerLimit), outerLimit) 10 ) 11 } 12 13 val a = new Service[HttpRequest, HttpResponse] { 14 def apply(req: HttpRequest) = for { 15 (offset, limit) <- pagination(req) 16 } yield Ok(s"offset $offset, limit $limit") 17 } 9
  • 10. Multi-Value Params 1 val reader = for { 2 a <- RequiredIntParams("a") 3 b <- RequiredIntParams("b") 4 } yield (a, b) 5 6 // request("a=1,2,3&b=4&b=5") 7 val (a, b): (List[Int], List[Int]) = reader(request) 8 // a = List(1, 2, 3) 9 // b = List(4, 5) 10
  • 11. Validation 1 val adult = for { 2 u <- user 3 _ <- ValidationRule("age", "should be greater then 18") { user.age >= 18 } 4 } yield u 5 6 val user: Future[User] = adult(request) handle { 7 case e: ParamNotFound => 8 BadRequest(JsonObject("param" -> e.param)) 9 case e: ValidationFailed => 10 BadRequest(JsonObject("param" -> e.param, "rule" -> e.rule)) 11 } 11
  • 12. Responses 1 // an empty response with status 200 2 val a = Ok() 3 4 // 'plain/text' response with status 404 5 val b = NotFound("body") 6 7 // 'application/json' response with status 201 8 val c = Created(JsonObject("id" -> 42)) 9 10 // 'plain/text' response of status 403 with custom header 11 val d = Forbidden.withHeaders("Some-Header-A" -> "a")("plain") 12
  • 13. JSON 1 // a : { 2 // b : 10, 3 // c : 20, 4 // d : 30 5 // } 6 val a = JsonObject("a.b" -> 10, "a.c" -> 20, "a.d" -> 30) 7 8 // a : { 9 // a : 100, 10 // b : 200 11 // } 12 val b = JsonObject("a.a" -> 100, "a.b" -> 200) 13 14 // a : { 15 // a : 100 16 // b : 200, 17 // c : 20, 18 // d : 30 19 // } 20 val c = JsonObject.mergeRight(a, b) 13
  • 14. Basic Auth 1 object ProtectedUser extends Endpoint[HttpRequest, HttpResponse] { 2 def route = { 3 case Method.Get -> Root / "users" => 4 BasicallyAuthorize("user", "password") ! 5 GetUsers 6 } 7 } 14
  • 15. Further Steps • Lightweight in-memory caching • Better JSON 15
  • 16. References § http://twitter.github.io/finagle/ ! § https://github.com/finagle/finch ! § https://github.com/finagle/finagle-oauth2 16
  • 17. Stay Finagled! ! And drop your feedbacks to @vkostyukov 17