SlideShare a Scribd company logo
THE FUNCTIONAL WEB STACK
HTTP4S, DOOBIE & CIRCE
Gary Coady
gcoady@gilt.com
LET’S BUILD A WEBSITE
• It’s going to be CRUD (create/read/update/delete)
• How do we convert data to/from database structure?
• How do we convert data to/from JSON?
• Converting from one format to another is most of a developer’s job!
CONVERTING TO/FROM JSON
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
“s”@JSON String
“t”@JSON Number
“i”@JSON Number
Json.obj(
“s”: Json.str,
“t”: Json.number,
“i”: Json.number)
Case Class JSON Object
CONVERTING TO/FROM JDBC
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
[0]@text
[1]@timestamptz
[2]@bigint
JDBC ResultSet(
0: text,
1: timestamptz,
2: bigint)
Case Class ResultSet
JDBC AND JSON COMBINED
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
[0]@text
[1]@timestamptz
[2]@bigint
JDBC ResultSet(
0: text,
1: timestamptz,
2: bigint)
Case Class ResultSet
“s”@JSON String
“t”@JSON Number
“i”@JSON Number
JSON Object
Json.obj(
“s”: Json.str,
“t”: Json.number,
“i”: Json.number)
JSON CONVERSION WITH CIRCE
• Very fast, usable JSON library
• Automatic derivation of JSON codecs for case classes
• Integration available with http4s
• http://circe.io
JSON CONVERSION WITH CIRCE
trait Encoder[A] {

def apply(a: A): Json

}
A => Json
java.time.Instant => Json
implicit val jsonEncoderInstant: Encoder[Instant] =

Encoder[Long].contramap(_.toEpochMilli)
JSON CONVERSION WITH CIRCE
trait Decoder[A] {

def apply(c: HCursor): Decoder.Result[A]

}
Json => A
implicit val jsonDecoderInstant: Decoder[Instant] =

Decoder[Long].map(Instant.ofEpochMilli)
Json => java.time.Instant
CONVERTING CASE CLASSES WITH CIRCE
Automatic
import io.circe.generic.auto._
Manual
// for case class Person(id: Int, name: String)
object Person {

implicit val decodePerson: Decoder[Person] =

Decoder.forProduct2("id", "name")(Person.apply)



implicit val encodePerson: Encoder[Person] =

Encoder.forProduct2("id", "name")(p =>

(p.id, p.name)

)

}
CONVERTING TO/FROM JSON
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
“s”@JSON String
“t”@JSON Number
“i”@JSON Number
Json.obj(
“s”: Json.str,
“t”: Json.number,
“i”: Json.number)
Case Class JSON Object
JDBC USING DOOBIE
• Doobie is a “pure functional JDBC layer for Scala”
• Complete representation of Java JDBC API
• https://github.com/tpolecat/doobie
• tpolecat.github.io/doobie-0.2.3/00-index.html (Documentation)
JDBC MAPPING WITH DOOBIE
sealed trait Meta[A] {

/** Destination JDBC types to which values of type `A` can be written. */

def jdbcTarget: NonEmptyList[JdbcType]



/** Source JDBC types from which values of type `A` can be read. */

def jdbcSource: NonEmptyList[JdbcType]



/** Constructor for a `getXXX` operation for type `A` at a given index. */

val get: Int => RS.ResultSetIO[A]


/** Constructor for a `setXXX` operation for a given `A` at a given index. */

val set: (Int, A) => PS.PreparedStatementIO[Unit] 



/** Constructor for an `updateXXX` operation for a given `A` at a given index. */

val update: (Int, A) => RS.ResultSetIO[Unit] 



/** Constructor for a `setNull` operation for the primary JDBC type, at a given index. */

val setNull: Int => PS.PreparedStatementIO[Unit]

}
JDBC MAPPING WITH DOOBIE
implicit val metaInstant =

Meta[java.sql.Timestamp].nxmap(

_.toInstant,

(i: Instant) => new java.sql.Timestamp(i.toEpochMilli)

)
Reusing an existing Meta definition
Meta definitions exist for:
Byte
Short
Int
Boolean
String
Array[Byte]
BigDecimal
Long
Float
Double
java.math.BigDecimal
java.sql.Time
java.sql.TimeStamp
java.sql.Date
java.util.Date
CONVERTING CASE CLASSES WITH DOOBIE
Nothing extra needed!
QUERIES WITH DOOBIE
sql"select id, name from people".query[Person]
Table "public.people"
Column | Type | Modifiers
---------------+--------------------------+-----------------------------------------------------
id | integer | not null default nextval('people_id_seq'::regclass)
name | text |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Given the table
Define a query
sql"select id, name from people where id = $id".query[Person]
Using prepared statements & variable interpolation
DEFINE THE EXPECTED RESULT SIZE
• myQuery.unique — Expect a single row from the query
• myQuery.option — Expect 0-1 rows from the query, return an Option
• myQuery.list — Return the results as a List
• myQuery.vector — Return the results as a Vector
• myQuery.process — Return the results as a stream of data
RUNNING QUERIES WITH DOOBIE
Define a Transactor for your Database
val xa = DriverManagerTransactor[Task](

"org.postgresql.Driver", "jdbc:postgresql:demo", "demo", ""

)
Run your query using the Transactor
myQuery.list.transact(xa)
Your query runs in a transaction (rollback on uncaught exception)
UPDATES WITH DOOBIE
Call .update instead of .query (returns number of rows modified)
def updatePerson(id: Int, name: String): ConnectionIO[Int] =
sql"update people set name=$name where id=$id"

.update
def updatePerson(id: Int, name: String): ConnectionIO[Person] =
sql"update people set name=$name where id=$id"

.update

.withUniqueGeneratedKeys("id", "name")
.withUniqueGeneratedKeys provides data from updated row
.withGeneratedKeys provides a stream of data, when multiple rows are updated
CONVERTING TO/FROM JDBC
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
[0]@text
[1]@timestamptz
[2]@bigint
JDBC ResultSet(
0: text,
1: timestamptz,
2: bigint)
Case Class ResultSet
JDBC AND JSON COMBINED
String
Instant
Int
case class MyClass(
s: String,
t: Instant,
i: Int)
[0]@text
[1]@timestamptz
[2]@bigint
JDBC ResultSet(
0: text,
1: timestamptz,
2: bigint)
Case Class ResultSet
“s”@JSON String
“t”@JSON Number
“i”@JSON Number
JSON Object
Json.obj(
“s”: Json.str,
“t”: Json.number,
“i”: Json.number)
HTTP4S
• http4s is a typeful, purely functional HTTP library for client and server
applications written in Scala
• http4s.org/
• https://github.com/http4s/http4s
• https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/
frameworks/Scala/http4s (from TechEmpower benchmarks)
• www.lyranthe.org/http4s/ (some programming guides)
WRITING A WEB SERVICE WITH HTTP4S
type HttpService = Service[Request, Response]
represents
Request => Task[Response]
Three requirements:
• Setup service
• Parse request
• Generate response
PATTERN MATCHING ON THE REQUEST
<METHOD> -> <PATH>
Extract Method and Path from Request
For example
case GET -> path
Root / "people" / id
Extract path components from Path
PATTERN MATCHING ON THE REQUEST
Extract typed components with extractors
import java.util.UUID



object UUIDVar {

def unapply(s: String): Option[UUID] = {

try {

UUID.fromString(s)

} catch {

case e: IllegalArgumentException =>

None

}

}

}
Root / "people" / UUIDVar(uuid)
PARSING REQUEST BODY
Register Circe as JSON decoder
implicit def circeJsonDecoder[A](implicit decoder: Decoder[A]) =
org.http4s.circe.jsonOf[A]
req.decode[Person] { person =>
...
}
Decode to a Person object
CREATING RESPONSE
Ok(Person(1, "Name"))
Output response code and any type with an EntityEncoder
Ok("Hello world")
Output response code and String as body
implicit def circeJsonEncoder[A](implicit encoder: Encoder[A]) =
org.http4s.circe.jsonEncoderOf[A]
PUTTING IT ALL TOGETHER
case class Person(id: Int, firstName: String, familyName: String, registeredAt: Instant)

case class PersonForm(firstName: String, familyName: String)
object PersonDAO {

implicit val metaInstant =

Meta[java.sql.Timestamp].nxmap(

_.toInstant,

(i: Instant) => new java.sql.Timestamp(i.toEpochMilli)

)



val listPeople: ConnectionIO[List[Person]] =

sql"select id, first_name, family_name, registered_at from people"

.query[Person]

.list



def getPerson(id: Long): ConnectionIO[Option[Person]] =

sql"select id, first_name, family_name, registered_at from people where id = $id"

.query[Person]

.option



def updatePerson(id: Int, firstName: String, familyName: String): ConnectionIO[Person] =

sql"update people set first_name=$firstName, family_name=$familyName where id=$id"

.update

.withUniqueGeneratedKeys("id", "first_name", "family_name", "registered_at")



def insertPerson(firstName: String, familyName: String, registeredAt: Instant = Instant.now()): ConnectionIO[Person] =

sql"insert into people (first_name, family_name, registered_at) values ($firstName, $familyName, $registeredAt)"

.update

.withUniqueGeneratedKeys("id", "first_name", "family_name", "registered_at")

}
PUTTING IT ALL TOGETHER
case class Person(id: Int, firstName: String, familyName: String, registeredAt: Instant)

case class PersonForm(firstName: String, familyName: String)
object DemoService {

implicit def circeJsonDecoder[A](implicit decoder: Decoder[A]) =
org.http4s.circe.jsonOf[A]


implicit def circeJsonEncoder[A](implicit encoder: Encoder[A]) =
org.http4s.circe.jsonEncoderOf[A]



def service(xa: Transactor[Task]) = HttpService {

case GET -> Root / "people" =>

Ok(PersonDAO.listPeople.transact(xa))



case GET -> Root / "people" / IntVar(id) =>

for {

person <- PersonDAO.getPerson(id).transact(xa)

result <- person.fold(NotFound())(Ok.apply)

} yield result



case req @ PUT -> Root / "people" / IntVar(id) =>

req.decode[PersonForm] { form =>

Ok(PersonDAO.updatePerson(id, form.firstName, form.familyName).transact(xa))

}



case req @ POST -> Root / "people" =>

req.decode[PersonForm] { form =>

Ok(PersonDAO.insertPerson(form.firstName, form.familyName).transact(xa))

}

}

}
PUTTING IT ALL TOGETHER
object Main {

def main(args: Array[String]): Unit = {

val xa = DriverManagerTransactor[Task](

"org.postgresql.Driver", "jdbc:postgresql:demo", "demo", ""

)



val server =

BlazeBuilder
.bindHttp(8080)

.mountService(DemoService.service(xa))

.run



server.awaitShutdown()

}

}
ADDING HTML TEMPLATING WITH TWIRL
Add to project/plugins.sbt
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.1.1")
Place templates in src/main/twirl
PACKAGING WITH SBT-NATIVE-PACKAGER
Add to project/plugins.sbt
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.1.0-RC1")
Enable AutoPlugin
enablePlugins(JavaServerAppPackaging)
STREAMING DATA WITH SCALAZ-STREAM
• Response can take a scalaz-stream Process
• Doobie can create a scalaz-stream Process from a Resultset
• Data sent incrementally using chunked Transfer-Encoding
val streamPeople: Process[ConnectionIO, Person] =

sql"select id, first_name, family_name, registered_at from people"

.query[Person]

.process
case GET -> Root / "stream" =>

Ok(PersonDAO.streamPeople.transact(xa).map(p => p.id + "n"))
QUESTIONS?
https://github.com/fiadliel/http4s-talk

More Related Content

What's hot

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
Scott Wlaschin
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
Scott Wlaschin
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
Philip Schwarz
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and Cats
Philip Schwarz
 
Python Workshop Part 2. LUG Maniapl
Python Workshop Part 2. LUG ManiaplPython Workshop Part 2. LUG Maniapl
Python Workshop Part 2. LUG Maniapl
Ankur Shrivastava
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and Functions
Jussi Pohjolainen
 
Express js
Express jsExpress js
Express js
Manav Prasad
 
JavaScript - Chapter 11 - Events
 JavaScript - Chapter 11 - Events  JavaScript - Chapter 11 - Events
JavaScript - Chapter 11 - Events
WebStackAcademy
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
Jorge Vásquez
 
JQuery selectors
JQuery selectors JQuery selectors
JQuery selectors
chandrashekher786
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Scott Wlaschin
 
Kleisli Composition
Kleisli CompositionKleisli Composition
Kleisli Composition
Philip Schwarz
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
Fabio Biondi
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
Scott Wlaschin
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
Scott Wlaschin
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
Oliver Daff
 
Monad Laws Must be Checked
Monad Laws Must be CheckedMonad Laws Must be Checked
Monad Laws Must be Checked
Philip Schwarz
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
RichardWarburton
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
Philip Schwarz
 

What's hot (20)

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and Cats
 
Python Workshop Part 2. LUG Maniapl
Python Workshop Part 2. LUG ManiaplPython Workshop Part 2. LUG Maniapl
Python Workshop Part 2. LUG Maniapl
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and Functions
 
Express js
Express jsExpress js
Express js
 
JavaScript - Chapter 11 - Events
 JavaScript - Chapter 11 - Events  JavaScript - Chapter 11 - Events
JavaScript - Chapter 11 - Events
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
JQuery selectors
JQuery selectors JQuery selectors
JQuery selectors
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Kleisli Composition
Kleisli CompositionKleisli Composition
Kleisli Composition
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
Monad Laws Must be Checked
Monad Laws Must be CheckedMonad Laws Must be Checked
Monad Laws Must be Checked
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 

Similar to Http4s, Doobie and Circe: The Functional Web Stack

Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Jim Czuprynski
 
Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.
Andrii Lashchenko
 
3 database-jdbc(1)
3 database-jdbc(1)3 database-jdbc(1)
3 database-jdbc(1)
hameedkhan2017
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke
 
JSON Fuzzing: New approach to old problems
JSON Fuzzing: New  approach to old problemsJSON Fuzzing: New  approach to old problems
JSON Fuzzing: New approach to old problems
titanlambda
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
Nelson Glauber Leal
 
ScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for Beginners
Kazuhiro Sera
 
Database Access With JDBC
Database Access With JDBCDatabase Access With JDBC
Database Access With JDBC
Dharani Kumar Madduri
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
leminhvuong
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
phanleson
 
OrientDB - The 2nd generation of (multi-model) NoSQL
OrientDB - The 2nd generation of  (multi-model) NoSQLOrientDB - The 2nd generation of  (multi-model) NoSQL
OrientDB - The 2nd generation of (multi-model) NoSQL
Roberto Franchini
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
Leonardo Soto
 
Lecture17
Lecture17Lecture17
Lecture17
vantinhkhuc
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
NoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryNoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love Story
Alexandre Morgaut
 
Requery overview
Requery overviewRequery overview
Requery overview
Sunghyouk Bae
 

Similar to Http4s, Doobie and Circe: The Functional Web Stack (20)

Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
 
Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.
 
3 database-jdbc(1)
3 database-jdbc(1)3 database-jdbc(1)
3 database-jdbc(1)
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
 
JSON Fuzzing: New approach to old problems
JSON Fuzzing: New  approach to old problemsJSON Fuzzing: New  approach to old problems
JSON Fuzzing: New approach to old problems
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
ScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for Beginners
 
Database Access With JDBC
Database Access With JDBCDatabase Access With JDBC
Database Access With JDBC
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commands
 
OrientDB - The 2nd generation of (multi-model) NoSQL
OrientDB - The 2nd generation of  (multi-model) NoSQLOrientDB - The 2nd generation of  (multi-model) NoSQL
OrientDB - The 2nd generation of (multi-model) NoSQL
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
 
Lecture17
Lecture17Lecture17
Lecture17
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
NoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryNoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love Story
 
Requery overview
Requery overviewRequery overview
Requery overview
 

Recently uploaded

Determination of Equivalent Circuit parameters and performance characteristic...
Determination of Equivalent Circuit parameters and performance characteristic...Determination of Equivalent Circuit parameters and performance characteristic...
Determination of Equivalent Circuit parameters and performance characteristic...
pvpriya2
 
Blood finder application project report (1).pdf
Blood finder application project report (1).pdfBlood finder application project report (1).pdf
Blood finder application project report (1).pdf
Kamal Acharya
 
SENTIMENT ANALYSIS ON PPT AND Project template_.pptx
SENTIMENT ANALYSIS ON PPT AND Project template_.pptxSENTIMENT ANALYSIS ON PPT AND Project template_.pptx
SENTIMENT ANALYSIS ON PPT AND Project template_.pptx
b0754201
 
Call Girls Chennai +91-8824825030 Vip Call Girls Chennai
Call Girls Chennai +91-8824825030 Vip Call Girls ChennaiCall Girls Chennai +91-8824825030 Vip Call Girls Chennai
Call Girls Chennai +91-8824825030 Vip Call Girls Chennai
paraasingh12 #V08
 
Beckhoff Programmable Logic Control Overview Presentation
Beckhoff Programmable Logic Control Overview PresentationBeckhoff Programmable Logic Control Overview Presentation
Beckhoff Programmable Logic Control Overview Presentation
VanTuDuong1
 
AI in customer support Use cases solutions development and implementation.pdf
AI in customer support Use cases solutions development and implementation.pdfAI in customer support Use cases solutions development and implementation.pdf
AI in customer support Use cases solutions development and implementation.pdf
mahaffeycheryld
 
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptxEV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
nikshimanasa
 
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICSUNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
vmspraneeth
 
Accident detection system project report.pdf
Accident detection system project report.pdfAccident detection system project report.pdf
Accident detection system project report.pdf
Kamal Acharya
 
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
upoux
 
Transformers design and coooling methods
Transformers design and coooling methodsTransformers design and coooling methods
Transformers design and coooling methods
Roger Rozario
 
Impartiality as per ISO /IEC 17025:2017 Standard
Impartiality as per ISO /IEC 17025:2017 StandardImpartiality as per ISO /IEC 17025:2017 Standard
Impartiality as per ISO /IEC 17025:2017 Standard
MuhammadJazib15
 
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
sydezfe
 
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
ijseajournal
 
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
Transcat
 
Levelised Cost of Hydrogen (LCOH) Calculator Manual
Levelised Cost of Hydrogen  (LCOH) Calculator ManualLevelised Cost of Hydrogen  (LCOH) Calculator Manual
Levelised Cost of Hydrogen (LCOH) Calculator Manual
Massimo Talia
 
This study Examines the Effectiveness of Talent Procurement through the Imple...
This study Examines the Effectiveness of Talent Procurement through the Imple...This study Examines the Effectiveness of Talent Procurement through the Imple...
This study Examines the Effectiveness of Talent Procurement through the Imple...
DharmaBanothu
 
Open Channel Flow: fluid flow with a free surface
Open Channel Flow: fluid flow with a free surfaceOpen Channel Flow: fluid flow with a free surface
Open Channel Flow: fluid flow with a free surface
Indrajeet sahu
 
Digital Image Processing Unit -2 Notes complete
Digital Image Processing Unit -2 Notes completeDigital Image Processing Unit -2 Notes complete
Digital Image Processing Unit -2 Notes complete
shubhamsaraswat8740
 
Assistant Engineer (Chemical) Interview Questions.pdf
Assistant Engineer (Chemical) Interview Questions.pdfAssistant Engineer (Chemical) Interview Questions.pdf
Assistant Engineer (Chemical) Interview Questions.pdf
Seetal Daas
 

Recently uploaded (20)

Determination of Equivalent Circuit parameters and performance characteristic...
Determination of Equivalent Circuit parameters and performance characteristic...Determination of Equivalent Circuit parameters and performance characteristic...
Determination of Equivalent Circuit parameters and performance characteristic...
 
Blood finder application project report (1).pdf
Blood finder application project report (1).pdfBlood finder application project report (1).pdf
Blood finder application project report (1).pdf
 
SENTIMENT ANALYSIS ON PPT AND Project template_.pptx
SENTIMENT ANALYSIS ON PPT AND Project template_.pptxSENTIMENT ANALYSIS ON PPT AND Project template_.pptx
SENTIMENT ANALYSIS ON PPT AND Project template_.pptx
 
Call Girls Chennai +91-8824825030 Vip Call Girls Chennai
Call Girls Chennai +91-8824825030 Vip Call Girls ChennaiCall Girls Chennai +91-8824825030 Vip Call Girls Chennai
Call Girls Chennai +91-8824825030 Vip Call Girls Chennai
 
Beckhoff Programmable Logic Control Overview Presentation
Beckhoff Programmable Logic Control Overview PresentationBeckhoff Programmable Logic Control Overview Presentation
Beckhoff Programmable Logic Control Overview Presentation
 
AI in customer support Use cases solutions development and implementation.pdf
AI in customer support Use cases solutions development and implementation.pdfAI in customer support Use cases solutions development and implementation.pdf
AI in customer support Use cases solutions development and implementation.pdf
 
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptxEV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
EV BMS WITH CHARGE MONITOR AND FIRE DETECTION.pptx
 
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICSUNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
 
Accident detection system project report.pdf
Accident detection system project report.pdfAccident detection system project report.pdf
Accident detection system project report.pdf
 
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
 
Transformers design and coooling methods
Transformers design and coooling methodsTransformers design and coooling methods
Transformers design and coooling methods
 
Impartiality as per ISO /IEC 17025:2017 Standard
Impartiality as per ISO /IEC 17025:2017 StandardImpartiality as per ISO /IEC 17025:2017 Standard
Impartiality as per ISO /IEC 17025:2017 Standard
 
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
 
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
 
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
Tools & Techniques for Commissioning and Maintaining PV Systems W-Animations ...
 
Levelised Cost of Hydrogen (LCOH) Calculator Manual
Levelised Cost of Hydrogen  (LCOH) Calculator ManualLevelised Cost of Hydrogen  (LCOH) Calculator Manual
Levelised Cost of Hydrogen (LCOH) Calculator Manual
 
This study Examines the Effectiveness of Talent Procurement through the Imple...
This study Examines the Effectiveness of Talent Procurement through the Imple...This study Examines the Effectiveness of Talent Procurement through the Imple...
This study Examines the Effectiveness of Talent Procurement through the Imple...
 
Open Channel Flow: fluid flow with a free surface
Open Channel Flow: fluid flow with a free surfaceOpen Channel Flow: fluid flow with a free surface
Open Channel Flow: fluid flow with a free surface
 
Digital Image Processing Unit -2 Notes complete
Digital Image Processing Unit -2 Notes completeDigital Image Processing Unit -2 Notes complete
Digital Image Processing Unit -2 Notes complete
 
Assistant Engineer (Chemical) Interview Questions.pdf
Assistant Engineer (Chemical) Interview Questions.pdfAssistant Engineer (Chemical) Interview Questions.pdf
Assistant Engineer (Chemical) Interview Questions.pdf
 

Http4s, Doobie and Circe: The Functional Web Stack

  • 1. THE FUNCTIONAL WEB STACK HTTP4S, DOOBIE & CIRCE Gary Coady gcoady@gilt.com
  • 2. LET’S BUILD A WEBSITE • It’s going to be CRUD (create/read/update/delete) • How do we convert data to/from database structure? • How do we convert data to/from JSON? • Converting from one format to another is most of a developer’s job!
  • 3. CONVERTING TO/FROM JSON String Instant Int case class MyClass( s: String, t: Instant, i: Int) “s”@JSON String “t”@JSON Number “i”@JSON Number Json.obj( “s”: Json.str, “t”: Json.number, “i”: Json.number) Case Class JSON Object
  • 4. CONVERTING TO/FROM JDBC String Instant Int case class MyClass( s: String, t: Instant, i: Int) [0]@text [1]@timestamptz [2]@bigint JDBC ResultSet( 0: text, 1: timestamptz, 2: bigint) Case Class ResultSet
  • 5. JDBC AND JSON COMBINED String Instant Int case class MyClass( s: String, t: Instant, i: Int) [0]@text [1]@timestamptz [2]@bigint JDBC ResultSet( 0: text, 1: timestamptz, 2: bigint) Case Class ResultSet “s”@JSON String “t”@JSON Number “i”@JSON Number JSON Object Json.obj( “s”: Json.str, “t”: Json.number, “i”: Json.number)
  • 6. JSON CONVERSION WITH CIRCE • Very fast, usable JSON library • Automatic derivation of JSON codecs for case classes • Integration available with http4s • http://circe.io
  • 7. JSON CONVERSION WITH CIRCE trait Encoder[A] {
 def apply(a: A): Json
 } A => Json java.time.Instant => Json implicit val jsonEncoderInstant: Encoder[Instant] =
 Encoder[Long].contramap(_.toEpochMilli)
  • 8. JSON CONVERSION WITH CIRCE trait Decoder[A] {
 def apply(c: HCursor): Decoder.Result[A]
 } Json => A implicit val jsonDecoderInstant: Decoder[Instant] =
 Decoder[Long].map(Instant.ofEpochMilli) Json => java.time.Instant
  • 9. CONVERTING CASE CLASSES WITH CIRCE Automatic import io.circe.generic.auto._ Manual // for case class Person(id: Int, name: String) object Person {
 implicit val decodePerson: Decoder[Person] =
 Decoder.forProduct2("id", "name")(Person.apply)
 
 implicit val encodePerson: Encoder[Person] =
 Encoder.forProduct2("id", "name")(p =>
 (p.id, p.name)
 )
 }
  • 10. CONVERTING TO/FROM JSON String Instant Int case class MyClass( s: String, t: Instant, i: Int) “s”@JSON String “t”@JSON Number “i”@JSON Number Json.obj( “s”: Json.str, “t”: Json.number, “i”: Json.number) Case Class JSON Object
  • 11. JDBC USING DOOBIE • Doobie is a “pure functional JDBC layer for Scala” • Complete representation of Java JDBC API • https://github.com/tpolecat/doobie • tpolecat.github.io/doobie-0.2.3/00-index.html (Documentation)
  • 12. JDBC MAPPING WITH DOOBIE sealed trait Meta[A] {
 /** Destination JDBC types to which values of type `A` can be written. */
 def jdbcTarget: NonEmptyList[JdbcType]
 
 /** Source JDBC types from which values of type `A` can be read. */
 def jdbcSource: NonEmptyList[JdbcType]
 
 /** Constructor for a `getXXX` operation for type `A` at a given index. */
 val get: Int => RS.ResultSetIO[A] 
 /** Constructor for a `setXXX` operation for a given `A` at a given index. */
 val set: (Int, A) => PS.PreparedStatementIO[Unit] 
 
 /** Constructor for an `updateXXX` operation for a given `A` at a given index. */
 val update: (Int, A) => RS.ResultSetIO[Unit] 
 
 /** Constructor for a `setNull` operation for the primary JDBC type, at a given index. */
 val setNull: Int => PS.PreparedStatementIO[Unit]
 }
  • 13. JDBC MAPPING WITH DOOBIE implicit val metaInstant =
 Meta[java.sql.Timestamp].nxmap(
 _.toInstant,
 (i: Instant) => new java.sql.Timestamp(i.toEpochMilli)
 ) Reusing an existing Meta definition Meta definitions exist for: Byte Short Int Boolean String Array[Byte] BigDecimal Long Float Double java.math.BigDecimal java.sql.Time java.sql.TimeStamp java.sql.Date java.util.Date
  • 14. CONVERTING CASE CLASSES WITH DOOBIE Nothing extra needed!
  • 15. QUERIES WITH DOOBIE sql"select id, name from people".query[Person] Table "public.people" Column | Type | Modifiers ---------------+--------------------------+----------------------------------------------------- id | integer | not null default nextval('people_id_seq'::regclass) name | text | Indexes: "people_pkey" PRIMARY KEY, btree (id) Given the table Define a query sql"select id, name from people where id = $id".query[Person] Using prepared statements & variable interpolation
  • 16. DEFINE THE EXPECTED RESULT SIZE • myQuery.unique — Expect a single row from the query • myQuery.option — Expect 0-1 rows from the query, return an Option • myQuery.list — Return the results as a List • myQuery.vector — Return the results as a Vector • myQuery.process — Return the results as a stream of data
  • 17. RUNNING QUERIES WITH DOOBIE Define a Transactor for your Database val xa = DriverManagerTransactor[Task](
 "org.postgresql.Driver", "jdbc:postgresql:demo", "demo", ""
 ) Run your query using the Transactor myQuery.list.transact(xa) Your query runs in a transaction (rollback on uncaught exception)
  • 18. UPDATES WITH DOOBIE Call .update instead of .query (returns number of rows modified) def updatePerson(id: Int, name: String): ConnectionIO[Int] = sql"update people set name=$name where id=$id"
 .update def updatePerson(id: Int, name: String): ConnectionIO[Person] = sql"update people set name=$name where id=$id"
 .update
 .withUniqueGeneratedKeys("id", "name") .withUniqueGeneratedKeys provides data from updated row .withGeneratedKeys provides a stream of data, when multiple rows are updated
  • 19. CONVERTING TO/FROM JDBC String Instant Int case class MyClass( s: String, t: Instant, i: Int) [0]@text [1]@timestamptz [2]@bigint JDBC ResultSet( 0: text, 1: timestamptz, 2: bigint) Case Class ResultSet
  • 20. JDBC AND JSON COMBINED String Instant Int case class MyClass( s: String, t: Instant, i: Int) [0]@text [1]@timestamptz [2]@bigint JDBC ResultSet( 0: text, 1: timestamptz, 2: bigint) Case Class ResultSet “s”@JSON String “t”@JSON Number “i”@JSON Number JSON Object Json.obj( “s”: Json.str, “t”: Json.number, “i”: Json.number)
  • 21. HTTP4S • http4s is a typeful, purely functional HTTP library for client and server applications written in Scala • http4s.org/ • https://github.com/http4s/http4s • https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/ frameworks/Scala/http4s (from TechEmpower benchmarks) • www.lyranthe.org/http4s/ (some programming guides)
  • 22. WRITING A WEB SERVICE WITH HTTP4S type HttpService = Service[Request, Response] represents Request => Task[Response] Three requirements: • Setup service • Parse request • Generate response
  • 23. PATTERN MATCHING ON THE REQUEST <METHOD> -> <PATH> Extract Method and Path from Request For example case GET -> path Root / "people" / id Extract path components from Path
  • 24. PATTERN MATCHING ON THE REQUEST Extract typed components with extractors import java.util.UUID
 
 object UUIDVar {
 def unapply(s: String): Option[UUID] = {
 try {
 UUID.fromString(s)
 } catch {
 case e: IllegalArgumentException =>
 None
 }
 }
 } Root / "people" / UUIDVar(uuid)
  • 25. PARSING REQUEST BODY Register Circe as JSON decoder implicit def circeJsonDecoder[A](implicit decoder: Decoder[A]) = org.http4s.circe.jsonOf[A] req.decode[Person] { person => ... } Decode to a Person object
  • 26. CREATING RESPONSE Ok(Person(1, "Name")) Output response code and any type with an EntityEncoder Ok("Hello world") Output response code and String as body implicit def circeJsonEncoder[A](implicit encoder: Encoder[A]) = org.http4s.circe.jsonEncoderOf[A]
  • 27. PUTTING IT ALL TOGETHER case class Person(id: Int, firstName: String, familyName: String, registeredAt: Instant)
 case class PersonForm(firstName: String, familyName: String) object PersonDAO {
 implicit val metaInstant =
 Meta[java.sql.Timestamp].nxmap(
 _.toInstant,
 (i: Instant) => new java.sql.Timestamp(i.toEpochMilli)
 )
 
 val listPeople: ConnectionIO[List[Person]] =
 sql"select id, first_name, family_name, registered_at from people"
 .query[Person]
 .list
 
 def getPerson(id: Long): ConnectionIO[Option[Person]] =
 sql"select id, first_name, family_name, registered_at from people where id = $id"
 .query[Person]
 .option
 
 def updatePerson(id: Int, firstName: String, familyName: String): ConnectionIO[Person] =
 sql"update people set first_name=$firstName, family_name=$familyName where id=$id"
 .update
 .withUniqueGeneratedKeys("id", "first_name", "family_name", "registered_at")
 
 def insertPerson(firstName: String, familyName: String, registeredAt: Instant = Instant.now()): ConnectionIO[Person] =
 sql"insert into people (first_name, family_name, registered_at) values ($firstName, $familyName, $registeredAt)"
 .update
 .withUniqueGeneratedKeys("id", "first_name", "family_name", "registered_at")
 }
  • 28. PUTTING IT ALL TOGETHER case class Person(id: Int, firstName: String, familyName: String, registeredAt: Instant)
 case class PersonForm(firstName: String, familyName: String) object DemoService {
 implicit def circeJsonDecoder[A](implicit decoder: Decoder[A]) = org.http4s.circe.jsonOf[A] 
 implicit def circeJsonEncoder[A](implicit encoder: Encoder[A]) = org.http4s.circe.jsonEncoderOf[A]
 
 def service(xa: Transactor[Task]) = HttpService {
 case GET -> Root / "people" =>
 Ok(PersonDAO.listPeople.transact(xa))
 
 case GET -> Root / "people" / IntVar(id) =>
 for {
 person <- PersonDAO.getPerson(id).transact(xa)
 result <- person.fold(NotFound())(Ok.apply)
 } yield result
 
 case req @ PUT -> Root / "people" / IntVar(id) =>
 req.decode[PersonForm] { form =>
 Ok(PersonDAO.updatePerson(id, form.firstName, form.familyName).transact(xa))
 }
 
 case req @ POST -> Root / "people" =>
 req.decode[PersonForm] { form =>
 Ok(PersonDAO.insertPerson(form.firstName, form.familyName).transact(xa))
 }
 }
 }
  • 29. PUTTING IT ALL TOGETHER object Main {
 def main(args: Array[String]): Unit = {
 val xa = DriverManagerTransactor[Task](
 "org.postgresql.Driver", "jdbc:postgresql:demo", "demo", ""
 )
 
 val server =
 BlazeBuilder .bindHttp(8080)
 .mountService(DemoService.service(xa))
 .run
 
 server.awaitShutdown()
 }
 }
  • 30. ADDING HTML TEMPLATING WITH TWIRL Add to project/plugins.sbt addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.1.1") Place templates in src/main/twirl
  • 31. PACKAGING WITH SBT-NATIVE-PACKAGER Add to project/plugins.sbt addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.1.0-RC1") Enable AutoPlugin enablePlugins(JavaServerAppPackaging)
  • 32. STREAMING DATA WITH SCALAZ-STREAM • Response can take a scalaz-stream Process • Doobie can create a scalaz-stream Process from a Resultset • Data sent incrementally using chunked Transfer-Encoding val streamPeople: Process[ConnectionIO, Person] =
 sql"select id, first_name, family_name, registered_at from people"
 .query[Person]
 .process case GET -> Root / "stream" =>
 Ok(PersonDAO.streamPeople.transact(xa).map(p => p.id + "n"))