Advertisement
Advertisement

More Related Content

Similar to Building a Reactive RESTful API with Akka Http & Slick(20)

Advertisement
Advertisement

Building a Reactive RESTful API with Akka Http & Slick

  1. Codemotion 2015, Berlin, Germany Building a Reactive RESTful API with Akka Http & Slick Dan Persa - @danpersa
  2. Dan Persa ● Senior Software Engineer ● Twitter: @danpersa ● dan.persa@zalando.de
  3. EUROPE’S LEADING ONLINE FASHION PLATFORM 15 countries 3 fulfillment centers 16+ million active customers 2.2+ billion € revenue 2014 130+ million visits per month 9.000+ employees Visit us: tech.zalando.com
  4. ZALANDO TECHNOLOGY
  5. 500+ Apps 800+ Tech employees August
  6. Conway’s Law “organizations which design systems ...are constrained to produce designs which are copies of the communication structures of these organizations”
  7. ARCHITECTURE AN ARCHITECTURE FOR INNOVATION
  8. API FIRST REST SAAS MICRO SERVICES CLOUD OPEN SOURCE
  9. THE SHOP MONOLITH
  10. http://blog.codinghorror.com/new-programming-jargon/ We call it “Jimmy”
  11. Thousands of Java classes, undocumented features Business logic on all layers (including the database)
  12. MICROSERVICES
  13. Internet LB SKIPPER SKIPPER SKIPPER SKIPPER JIMMY MOSAIC INNKEEPER INNKEEPER INNKEEPERLB REST APIs
  14. HIGHLY AVAILABLE 0 DOWNTIME RELIABLE FAST
  15. INNKEEPER github.com/zalando/innkeeper
  16. API FIRST REST
  17. FORMAL SPECIFICATION FOR RESTful APIs The World's Most Popular Framework for APIs.
  18. REST RESOURCES GET /routes GET /routes/{id} POST /routes DELETE /routes/{id} GET /updated- routes/{id}
  19. GOING REACTIVE
  20. MODEL DBCONTROLLER BUFFERBUFFER DB RecordsDTOsJSON CLIENT TRADITIONAL APPLICATION HTTP Request Method Call SQL Blocking IO
  21. MODEL DBCONTROLLER DB StreamDTOsJSON CLIENT REACTIVE APPLICATION HTTP Request Method Call SQL Non-Blocking IO StreamStreamStream
  22. Scala Typesafe Composable Meet
  23. Separation of I/0 Resilience Reactive Streams Meet
  24. def routesModifiedSince(localDateTime: LocalDateTime): DatabasePublisher[RouteRow] = { } val routesTable = TableQuery[RoutesTable] val q = for { routeRow <- routesTable if (routeRow.createdAt > localDateTime | routeRow.deletedAt > localDateTime) } yield routeRow db.stream { q.result }
  25. Composable Materializable Reactive Streams Meet Streams
  26. import akka.stream.scaladsl.Source def findRoutesModifiedSince(localDateTime: LocalDateTime): Source[Route, Unit] = { } Source( ).mapConcat(_.toList) routesRepo.selectModifiedSince(localDateTime).mapResult { row => } row.id.map { id => Route( id = id, route = row.routeJson.parseJson.convertTo[NewRoute], row.createdAt, row.deletedAt ) }
  27. val route = path("hello") { get { complete { <h1>Hello World</h1> } } } Meet Http
  28. object Main extends App { } implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() val route = ... val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) ...
  29. Innkeeper’s AKKA HTTP Routes val route = path("updated-routes" / Rest) { lastModifiedString => get { complete(…) } } ~ path("routes") { get { complete(…) } ~ post { complete(…) } } ~ path("routes" / LongNumber) { id => get { … } ~ delete { … } }
  30. path("routes") { get { complete { HttpResponse( ) } } } entity = HttpEntity.Chunked( MediaTypes.`application/json`, chunkedStreamSource ) val chunkedStreamSource = jsonService.sourceToJsonSource(routesService.allRoutes)
  31. def sourceToJsonSource[T](source: Source[T, Unit]) (implicit writer: JsonWriter[T]): Source[ChunkStreamPart, ((Unit, Unit), Unit)] = { val commaSeparatedRoutes: Source[ChunkStreamPart, Unit] = source .map(t => Some(t.toJson.compactPrint)) .scan[Option[ChunkStreamPart]](None)({ case (None, Some(sourceElement)) => Some(ChunkStreamPart(sourceElement)) case (_, Some(sourceElement)) => Some(ChunkStreamPart(s", $sourceElement")) }) .mapConcat(_.toList) Source.single(ChunkStreamPart("[")) ++ commaSeparatedRoutes ++ Source.single(ChunkStreamPart("]")) }
  32. SAAS
  33. OAUTH
  34. val route: RequestContext => Future[RouteResult] = authenticationToken { token => authenticate(token, authService) { authenticatedUser => path("updated-routes" / Rest) { lastModifiedString => get { hasOneOfTheScopes(authenticatedUser)(scopes.READ) { ...
  35. import akka.http.scaladsl._ import akka.http.scaladsl.server.directives.HeaderDirectives._ trait OAuthDirectives { def authenticationToken: Directive1[String] = headerValue(optionalValue("authorization")) | reject { AuthenticationFailedRejection( CredentialsMissing, HttpChallenge("", "") ) } ...
  36. CLOUD
  37. STUPS.IO
  38. FROM zalando/openjdk:8u45-b14-5 MAINTAINER Team Spearheads <team-spearheads@zalando.de> EXPOSE 8080 RUN mkdir -p /opt/innkeeper ADD target/scala-2.11/innkeeper-assembly-0.0.1.jar /opt/innkeeper/ WORKDIR /opt/innkeeper ENTRYPOINT java $(java-dynamic-memory-opts) -Dinnkeeper.env=prod -server -jar innkeeper-assembly-0.0.1.jar
  39. docker: sbt assembly docker build -t innkeper:latest-SNAPSHOT . docker-push: docker push innkeper:latest-SNAPSHOT docker-run: docker run -p 8080:8080 -t innkeper:latest-SNAPSHOT test-db: docker run -e POSTGRES_PASSWORD=innkeeper-test -e POSTGRES_USER=innkeeper-test -p 5433:5432 postgres:9.4 tick: senza create senza.yaml tick latest-SNAPSHOT tock: senza create senza.yaml tock latest-SNAPSHOT
  40. OPEN SOURCE
  41. github.com/zalando/innkeeper
  42. DO OSF
  43. RADICAL AGILITY TRUST INSTEAD OF CONTROL
  44. # use Docker-based container (instead of OpenVZ) sudo: false cache: directories: - $HOME/.sbt - $HOME/.ivy2 language: scala script: - sbt ++$TRAVIS_SCALA_VERSION test - sbt ++$TRAVIS_SCALA_VERSION it:test # Trick to avoid unnecessary cache updates - find $HOME/.sbt -name "*.lock" | xargs rm scala: - 2.11.7 jdk: - oraclejdk8 addons: postgresql: "9.4" before_script: - psql -c 'CREATE ROLE innkeepertest superuser login createdb;' -U postgres - psql -c 'CREATE DATABASE innkeepertest;' -U postgres
  45. NEXT STEPS
  46. APPLICATION LOGS: SCALYR
  47. TODO: Screenshot ZMON
  48. Where to Find Us: Tech Blog: tech.zalando.com GitHub: github.com/zalando Innkeeper: github.com/zalando/innkeeper Twitter: @ZalandoTech Instagram: zalandotech Jobs: http://tech.zalando.com/jobs
  49. THANK YOU! QUESTIONS?
Advertisement