Slide 1

Slide 1 text

Building APIs in Scala with Play! Framework 2 Silicon Valley Code Camp Oct 5th, 2013 Manish Pandit @lobster1234

Slide 2

Slide 2 text

Manish Pandit @lobster1234 mpandit@netflix.com linkedin.com/in/mpandit slideshare.net/lobster1234

Slide 3

Slide 3 text

Agenda Scala Typesafe Platform PlayFramework REST Hands-on API Open Floor

Slide 4

Slide 4 text

Scala Concise, yet expressive Statically Typed via Type Inference Rich Constructs Functions as First Class Citizens Power of DSL Interoperability with the Java Ecosystem

Slide 5

Slide 5 text

Typesafe Platform Scala Programming Language PlayFramework for Web Applications sbt for builds Akka Typesafe Activator Misc. Tools

Slide 6

Slide 6 text

Typesafe Activator A very simple way to start with Scala and Play! Applications Browser-based Interactive Comes with a good number of templates

Slide 7

Slide 7 text

Typesafe Activator

Slide 8

Slide 8 text

Typesafe Activator Use if you do not have an IDE Use it to play with various templates it comes with Yet to mature but a (very) good start

Slide 9

Slide 9 text

Play! Framework Simple Convention over Configuration Focus on Developer Productivity Asynchronous Processing Model Makes testing easy JSON support for RESTFul Applications

Slide 10

Slide 10 text

Play! Framework Not a J2EE compatible framework Does not follow the traditional request/response model

Slide 11

Slide 11 text

Creating a Play! Project

Slide 12

Slide 12 text

Using an IDE

Slide 13

Slide 13 text

Eclipse Import

Slide 14

Slide 14 text

Gotchas! Start with a fresh installation of ScalaIDE Go to Install New Software – Select ScalaIDE – Check Play2 Plugin

Slide 15

Slide 15 text

Run the App!

Slide 16

Slide 16 text

And Play! with it http://localhost:9000 Test the app with play test

Slide 17

Slide 17 text

Play! Core Concepts Uses sbt as the build system (In a special way to support always-on builds)

Slide 18

Slide 18 text

Play! Core Concepts MVC Folder Structure Controllers Routes File Tests

Slide 19

Slide 19 text

Play! Actions In simple terms, an Action takes function, that takes a request Request, and returns a Response.

Slide 20

Slide 20 text

Play! Actions All routable methods of a Controller are Actions (Request => Result) function

Slide 21

Slide 21 text

The almighty Action A simple, no-request that returns a result. A function that makes the Request available to the block You can pass a BodyParser to the Action as an argument Default BodyParsers are available for common content types

Slide 22

Slide 22 text

Play! Console Demo run vs. ~run With ~ run or run, change the app with syntax error Fix the app and retry Use the app with ~ test in Play! Console Change the code and watch the tests fail Change the tests and watch them pass

Slide 23

Slide 23 text

The Routes file Type-safe way to define mappings from URLs to Actions Rich support for basic data types Handling of defaults

Slide 24

Slide 24 text

RESTFul APIs Not JSON over HTTP Not JSON representation of your Database No Spec or official standard

Slide 25

Slide 25 text

RESTFul APIs Envision the entities as HTTP resources Envision the interactions as HTTP methods Read RFC 2616

Slide 26

Slide 26 text

Play! Hands-on API Model – A Person APIs – Get all, Get by First/Last/Zip, Add a person JSON Request and Response

Slide 27

Slide 27 text

Model object PersonModel { val persons = ArrayBuffer(Person("Manish", "Pandit", 94568), Person("John", "Doe", 95051), Person("My", "Neighbor", 94568)) def add(p: Person) = persons += p def getAll = persons def getByFirstName(first: String) = persons.filter(_.first == first) def getByLastName(last: String) = persons.filter(_.last == last) def getByZip(zip: Int) = persons.filter(_.zip == zip) } case class Person(first: String, last: String, zip: Int)

Slide 28

Slide 28 text

Controller object SimpleAPI extends Controller { implicit val personWrites = Json.writes[Person] implicit val personReads = Json.reads[Person] def getAll = Action { Ok(Json.toJson(PersonModel.getAll)) } def add = Action(parse.json) { request => Logger.info(s"Body is $request.body") request.body.validate(personReads) match { case x: JsError => BadRequest case x: JsSuccess[Person] => PersonModel.add(x.get) Created } } def getByFirstName(first: String) = Action { val list = PersonModel.getByFirstName(first) if (list.isEmpty) NotFound else Ok(Json.toJson(PersonModel.getByFirstName(first))) } }

Slide 29

Slide 29 text

Routes #  ~~~~   # Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Home page GET /persons controllers.SimpleAPI.getAll GET /persons/first/:first controllers.SimpleAPI.getByFirstName(first) GET /persons/last/:last controllers.SimpleAPI.getByLastName(last) GET /persons/zip/:zip controllers.SimpleAPI.getbyZip(zip:Int) GET /persons/default controllers.SimpleAPI.getByFirstName(first="Manish") POST /persons controllers.SimpleAPI.add

Slide 30

Slide 30 text

Play! Packaging Use play dist to package the app as a zip file Run using the start script

Slide 31

Slide 31 text

Play! Advanced Topics Reactive Programming Akka, Futures, Promises Play WS Library Anorm and Slick

Slide 32

Slide 32 text

Further reading http://www.playframework.com/ http://typesafe.com/platform StackOverflow Source : https://github.com/lobster1234/SVCC2013

Slide 33

Slide 33 text

We are hiring! netflix.github.io techblog.netflix.com jobs.netflix.com

Slide 34

Slide 34 text

Fin Manish Pandit @lobster1234 mpandit@netflix.com linkedin.com/in/mpandit slideshare.net/lobster1234