Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Finch + Finagle-OAuth2
=
Purely Functional REST API
Vladimir Kostyukov
@vkostyukov
Finagle-OAuth2: Highlights
• Asynchronous version of Nulab’s scala-oauth2-provider
!
• Finagle-friendly API: OAuth2Request...
1 trait DataHandler[U] {	
2 ... 	
3 def findUser(username: String, password: String): Future[Option[U]]	
4 def createAcces...
Finagle-OAuth2: Step #2
Typesafe Auth
1 import com.twitter.finagle.oauth2._	
2 import com.twitter.finagle.oauth2.{OAuth2Fi...
1 import com.twitter.finagle.oauth2._	
2 import com.twitter.finagle.oauth2.OAuth2Endpoint	
3 	
4 val tokens: Service[Reque...
Thin layer of purely-functional basic blocks
on top of Finagle for building composable
REST APIs
Finch
https://github.com/...
Finch: Highlights
• Was #1 Scala trending repo on GitHub for 95 mins
!
!
!
!
!
!
!
• Happily used in production by 2 custo...
Finch: Quickstart
1 def hello(name: String) = new Service[HttpRequest, HttpResponse] = {	
2 def apply(req: HttpRequest) = ...
Finch: Request Reader
(Reader Monad)
1 trait RequestReader[A] {	
2 	
3 def apply(req: HttpRequest): Future[A]	
4 	
5 def f...
Finch: Request Reader
1 val pagination: RequestReader[(Int, Int)] = for {	
2 offset <- OptionalIntParam("offset")	
3 limit...
Finch: Params Validation
1 case class User(age: Int)	
2 	
3 val user: RequestReader[User] = 	
4 for { age <- RequiredIntPa...
Finch:
Request Reader Highlights
• RequiredParam, RequiredIntParam, etc 	
• Future.value[A]	
• Future.exception[ParamNotFo...
Finch: Responses
1 // empty response with status 200	
2 val a = Ok()	
3 	
4 // 'plain/text' response with status 404	
5 va...
Finch: Endpoints Highlights
• Finch’s Endpoints are composable routers
!
• Endpoints might be treated as Scala’s
PartialFu...
Finch:
Endpoints Composition
1 val ab: Filter[A, C, B, C] = ???	
2 val bc: Endpoint[B, C] = ???	
3 val cd: Service[C, D]	
...
Finagle rocks!
16
• A better JSON
• Lightweight in-memory caching API
Finch: Further Steps
17
• https://github.com/finagle/finch
• https://github.com/finagle/finagle-oauth2
Resources
@vkostyukov
18
Upcoming SlideShare
Loading in …5
×

Finch + Finagle OAuth2

2,349 views

Published on

Slides from my talk at Finagle Meetup at Twitter.

Published in: Engineering
  • Be the first to comment

Finch + Finagle OAuth2

  1. 1. Finch + Finagle-OAuth2 = Purely Functional REST API Vladimir Kostyukov @vkostyukov
  2. 2. Finagle-OAuth2: Highlights • Asynchronous version of Nulab’s scala-oauth2-provider ! • Finagle-friendly API: OAuth2Request, OAuth2Filter ! • Does not depend on Finch 2
  3. 3. 1 trait DataHandler[U] { 2 ... 3 def findUser(username: String, password: String): Future[Option[U]] 4 def createAccessToken(authInfo: AuthInfo[U]): Future[AccessToken] 5 def getStoredAccessToken(authInfo: AuthInfo[U]): Future[Option[AccessToken]] 6 def findAccessToken(token: String): Future[Option[AccessToken]] 7 ... 8 } Finagle-OAuth2: Step #1 DataHandler 3
  4. 4. Finagle-OAuth2: Step #2 Typesafe Auth 1 import com.twitter.finagle.oauth2._ 2 import com.twitter.finagle.oauth2.{OAuth2Filter, OAuth2Request} 3 4 val auth = new OAuth2Filter(dataHandler) 5 6 val hello = new Service[OAuth2Request[User], Response] { 7 def apply(req: OAuth2Request[User]) = { 8 println(s"Hello, ${req.authInfo.user}!") 9 Future.value(Response()) 10 } 11 } 12 13 val backend: Service[Request, Response] = auth andThen hello 4
  5. 5. 1 import com.twitter.finagle.oauth2._ 2 import com.twitter.finagle.oauth2.OAuth2Endpoint 3 4 val tokens: Service[Request, Response] = 5 new OAuth2Endpoint(dataHandler) with OAuthErrorInJson with OAuthTokenInJson Finagle-OAuth2: Step #3 Issue Acces Token 5
  6. 6. Thin layer of purely-functional basic blocks on top of Finagle for building composable REST APIs Finch https://github.com/finagle/finch 6
  7. 7. Finch: Highlights • Was #1 Scala trending repo on GitHub for 95 mins ! ! ! ! ! ! ! • Happily used in production by 2 customers: • Konfettin • JusBrasil ! • Super simple & lightweight (~ 1.5k SLOC) 7
  8. 8. Finch: 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 => 11 BasicallyAuthorize("user", "password") ! hello(name) 12 } 13 } 14 15 val service: Service[HttpRequest, HttpResponse] = endpoint.toService 8
  9. 9. Finch: Request Reader (Reader Monad) 1 trait RequestReader[A] { 2 3 def apply(req: HttpRequest): Future[A] 4 5 def flatMap[B](fn: A => RequestReader[B]): RequestReader[B] = ??? 6 7 def map[B](fn: A => B): RequestReader[B] = ??? 8 } 9
  10. 10. Finch: Request Reader 1 val pagination: RequestReader[(Int, Int)] = for { 2 offset <- OptionalIntParam("offset") 3 limit <- OptionalIntParam("limit") 4 } yield (offset.getOrElse(0), math.min(limit.getOrElse(50), 50)) 5 6 val service = new Service[HttpRequest, HttpResponse] { 7 def apply(req: HttpRequest) = for { 8 (offsetIt, limit) <- pagination(req) 9 } yield Ok(s"Fetching items $offset..${offset+limit}") 10 } 10
  11. 11. Finch: Params Validation 1 case class User(age: Int) 2 3 val user: RequestReader[User] = 4 for { age <- RequiredIntParam("age") } yield User(age) 5 6 val adult: RequestReader[User] = for { 7 u <- user 8 _ <- ValidationRule("age", "should be greater then 18") { user.age > 18 } 9 } yield u 10 11 val u: Future[JsonResponse] = adult(request) map { 12 JsonObject("age" -> _.age) 13 } handle { 14 case e: ParamNotFound => 15 JsonObject("error" -> e.getMessage, "param" -> e.param) 16 case e: ValidationFailed => 17 JsonObject("error" -> e.getMessage, "param" -> e.param) 18 } 11
  12. 12. Finch: Request Reader Highlights • RequiredParam, RequiredIntParam, etc • Future.value[A] • Future.exception[ParamNotFound] ! • OptionalParam, OptionalIntParam, etc • Future.value[Option[A]] ! • Multi-value Params: RequiredParams, OptionalIntParams, etc. • Future.value[List[A]] ! • Params Validation: ValidationRule • Future.value[Unit] • Future.exception[ValidationFailed] 12
  13. 13. Finch: Responses 1 // 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" -> 100)) 9 10 // ‘plain/text' response with custom header and status 403 11 val d = Forbidden.withHeaders("Some-Header" -> "Secret")("body") 13
  14. 14. Finch: Endpoints Highlights • Finch’s Endpoints are composable routers ! • Endpoints might be treated as Scala’s PartialFunctions[Request, Service[_, _]] ! • Endpoints are convertible to Finagle Service’s ! • Endpoints might be composed with Service’s, Filter’s or other Endpoint’s. 14
  15. 15. Finch: Endpoints Composition 1 val ab: Filter[A, C, B, C] = ??? 2 val bc: Endpoint[B, C] = ??? 3 val cd: Service[C, D] 4 5 val ad1: Endpoint[A, D] = ab ! bc ! cd 6 val ad2: Endpoint[A, D] = ??? 7 8 val ad3: Endpoint[A, D] = ad1 orElse ad2 15
  16. 16. Finagle rocks! 16
  17. 17. • A better JSON • Lightweight in-memory caching API Finch: Further Steps 17
  18. 18. • https://github.com/finagle/finch • https://github.com/finagle/finagle-oauth2 Resources @vkostyukov 18

×