SlideShare ist ein Scribd-Unternehmen logo
1 von 33
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaVladimir Kostyukov
 
non-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parametersnon-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parametersPhilip Schwarz
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
RxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixRxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixTracy Lee
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in ScalaHermann Hueck
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)Scott Wlaschin
 
Queue Data Structure
Queue Data StructureQueue Data Structure
Queue Data StructureZidny Nafan
 
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 FoldPhilip Schwarz
 
Capabilities for Resources and Effects
Capabilities for Resources and EffectsCapabilities for Resources and Effects
Capabilities for Resources and EffectsMartin Odersky
 
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017Hardik Trivedi
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022Alexander Ioffe
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...Philip Schwarz
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
Bca ii dfs u-2 linklist,stack,queue
Bca ii  dfs u-2 linklist,stack,queueBca ii  dfs u-2 linklist,stack,queue
Bca ii dfs u-2 linklist,stack,queueRai University
 
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...Philip Schwarz
 
The Expression Problem - Part 1
The Expression Problem - Part 1The Expression Problem - Part 1
The Expression Problem - Part 1Philip Schwarz
 

Was ist angesagt? (20)

Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in Scala
 
non-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parametersnon-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parameters
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Applicative Functor
Applicative FunctorApplicative Functor
Applicative Functor
 
RxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixRxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMix
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in Scala
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
Queue Data Structure
Queue Data StructureQueue Data Structure
Queue Data Structure
 
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
 
Capabilities for Resources and Effects
Capabilities for Resources and EffectsCapabilities for Resources and Effects
Capabilities for Resources and Effects
 
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
Bca ii dfs u-2 linklist,stack,queue
Bca ii  dfs u-2 linklist,stack,queueBca ii  dfs u-2 linklist,stack,queue
Bca ii dfs u-2 linklist,stack,queue
 
Recursion
RecursionRecursion
Recursion
 
C Programming
C ProgrammingC Programming
C Programming
 
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
 
Zio in real world
Zio in real worldZio in real world
Zio in real world
 
The Expression Problem - Part 1
The Expression Problem - Part 1The Expression Problem - Part 1
The Expression Problem - Part 1
 

Ähnlich wie 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 21cJim 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
 
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 problemstitanlambda
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using RoomNelson Glauber Leal
 
ScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersKazuhiro Sera
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commandsphanleson
 
Executing Sql Commands
Executing Sql CommandsExecuting Sql Commands
Executing Sql Commandsleminhvuong
 
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) NoSQLRoberto Franchini
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi 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
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
NoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryNoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryAlexandre Morgaut
 

Ähnlich wie 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
 

Kürzlich hochgeladen

Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionDr.Costas Sachpazis
 
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfme23b1001
 
Piping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringPiping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringJuanCarlosMorales19600
 
Transport layer issues and challenges - Guide
Transport layer issues and challenges - GuideTransport layer issues and challenges - Guide
Transport layer issues and challenges - GuideGOPINATHS437943
 
Introduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHIntroduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHC Sai Kiran
 
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)dollysharma2066
 
complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...asadnawaz62
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleAlluxio, Inc.
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...Chandu841456
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.eptoze12
 
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEINFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEroselinkalist12
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncssuser2ae721
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxKartikeyaDwivedi3
 
Indian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptIndian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptMadan Karki
 
Earthing details of Electrical Substation
Earthing details of Electrical SubstationEarthing details of Electrical Substation
Earthing details of Electrical Substationstephanwindworld
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfROCENODodongVILLACER
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AIabhishek36461
 
Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvLewisJB
 

Kürzlich hochgeladen (20)

Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
 
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdf
 
Piping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringPiping Basic stress analysis by engineering
Piping Basic stress analysis by engineering
 
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
 
Transport layer issues and challenges - Guide
Transport layer issues and challenges - GuideTransport layer issues and challenges - Guide
Transport layer issues and challenges - Guide
 
Introduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHIntroduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECH
 
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)
Call Us ≽ 8377877756 ≼ Call Girls In Shastri Nagar (Delhi)
 
complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
 
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.
 
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEINFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptx
 
Indian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptIndian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.ppt
 
Earthing details of Electrical Substation
Earthing details of Electrical SubstationEarthing details of Electrical Substation
Earthing details of Electrical Substation
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdf
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AI
 
Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvv
 

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"))