3. Why we've used Play2 and Slick?
● Many users and developers
● Future prospects
● Supported by Typesafe
4. Dissatisfaction to Play2
● Unnecessary features
○ View support
○ Assets management
○ Dependency injection
● Poor integration
○ Zipkin https://github.com/levkhomich/akka-tracing
○ Swagger https://github.com/swagger-api/swagger-play
5. Dissatisfaction to Slick
● Lerning curve
○ DBIO is hard for non-functional programmers
○ Asynchronous is not always needed
● Performance
○ Join makes subquery frequently
○ It causes performance issue with MySQL
8. Finagle
● Pluggable asynchronous RPC framework
based on Netty
● Client API with Circuit Breaker
● Zipkin integration
● Finatra or Finch for HTTP server
● Swagger 1.x support for Finatra (3rd party)
○ https://github.com/xiaodongw/swagger-finatra
9. Finagle
val router = RoutingService.byPathObject[Request] {
case Root => new Service[Request,Response] {
def apply(req: Request): Future[Response] = {
Future(Response(
req.version, Status.Ok, Reader.fromBuf(Utf8("API is Ready."))
))
}
}
case Root / "hello"/ name => new Service[Request, Response] {
def apply(req: Request): Future[Response] = {
Future(Response(
req.version, Status.Ok, Reader.fromBuf(Utf8(s"Hello ${name}!"))
))
}
}
}
Maybe Finatra or Finch is better choise for REST API server
10. Akka HTTP
● Actor-based toolkit for interacting web
services and clients
● spray like routing DSL
● Reactive Streams
● Swagger 2.0 support (3rd party)
○ https://github.com/swagger-akka-http/swagger-akka-http
● Play 3.0 will move to Akka HTTP?
○ Experimental in Play 2.5
○ https://www.playframework.com/documentation/2.5.x/AkkaHttpServer
11. Akka HTTP
val route = get {
pathEndOrSingleSlash {
handleWith((request: HttpRequest) => "API is ready.")
}
} ~ path("hello" / ".+".r) {
get { case (name) =>
complete {
HelloResult(message = s"Hello, ${request.name}!")
}
}
}
12. Skiny Micro
● Servlet-based micro framework
● Scalatra comparible routing DSL
● Future-wired async operation
● No Swagger and Zipkin support
14. Results
Version View DI Routing Circuit
Breaker
Reactive
Streams
Zipkin Swagger
Play2 2.5.8 Supported Guice Method +
DSL
- ※2 3rd party
library
3rd party
library
Finagle 6.38.0 - ※1 DSL Supported - Supported 3rd party
library
Akka HTTP 2.4.10-exp
erimantal
- - DSL - Supported 3rd party
library
3rd party
library
Skinny
Micro
1.1.0 - - DSL - - - -
※1 Finatra is equipped Guice based dependency injection as same as Play2
※2 There is an experimental module in Play 2.5
https://www.playframework.com/documentation/2.5.x/ReactiveStreamsIntegration
15. Quill
● Macro-based compile time SQL generation
○ No overhead in runtime
○ Compile time SQL validation is available
○ Some constraints in query building
● Development is very active
○ Many sub modules are available such as async,
cassandra support and finagle integration
● Move to scala.meta in the future?
20. Quill
SELECT ...
FROM account t
WHERE CASE WHEN ? THEN
t.mail_address = ?
ELSE
(t.mail_address = ?) AND (t.removed = false)
END
No, translated to CASE expression
21. doobie
● A pure-functional JDBC layer for Scala
○ It is not an ORM
● Designed for people who are interested in:
○ typed
○ pure functional programming
● IO and monadic effects
22. doobie
sql"select * from account where uid = $id"
.query[Account]
.option
.transact(xa)
.unsafePerformAsync {
case -/(throwable) => ...
case /-(account) => ...
}
23. doobie
sql"select * from account where uid = $id"
.query[Account] // Query0[Account]
.option // ConnectionIO[Option[Account]]
.transact(xa) // Task[Option[Account]]
.unsafePerformAsync {
case -/(throwable) => … // Throwable
case /-(account) => … // Option[Account]
}
Query0[Account] is all columns query that maps one returned row.
Ultimately producing a value of type Option[Account].
24. doobie
sql"select * from account where uid = $id"
.query[Account] // Query0[Account]
.option // ConnectionIO[Option[Account]]
.transact(xa) // Task[Option[Account]]
.unsafePerformAsync {
case -/(throwable) => … // Throwable
case /-(account) => … // Option[Account]
}
Task is scalaz.concurrent.Task!!
25. doobie
● Typechecking (experimental)
○ Validate queries against the database schema in
runtime
val q: Query0[Account] =
sql"select * from account where uid = $id".query[Account]
q.check.unsafePerformSync
✓ SQL Compiles and Typechecks
✕ C01 UID INTEGER (INTEGER) NOT NULL → String
- INTEGER (INTEGER) is ostensibly coercible to String according to the JDBC
specification but is not a recommended target type. Fix this by changing the
schema type to CHAR or VARCHAR; or the Scala type to Int or JdbcType.
✓ C02 LOGIN_ID VARCHAR (VARCHAR) NOT NULL → String
26. ScalikeJDBC
● A tidy SQL-based DB access library for
Scala
○ Naturally wrap JDBC APIs
○ easy-to-use
● QueryDSL is available (since 1.6)
27. ScalikeJDBC
val id = 1
// QueryDSL
val a = Account.syntax("a")
val account: Option[Account] = DB readOnly { implicit s =>
withSQL {
select.from(Account as a).where.eq(a.uid, id)
}.map(Account(a)).single.apply()
}
28. ScalikeJDBC
val id = 1
case class Email(name: String, address: String)
// basic SQL
val email: Option[Email] = DB readOnly { implicit s =>
sql"select * from account where uid = ${id}"
.map(rs =>
Email(rs.get("name"), rs.get("mail_address"))
).single.apply()
}
29. Results
Version Monad Async Mapping Typesafe
DSL
Genarated
SQL
Timing PlainSQL
Slick 3.1.1 Required Always Required
※2
Supported Non-intuitiv
e
Runtime Supported
Quill 0.10.0 Option ※1 - Supported
※3
Intuitive Compile
time
-
doobie 0.3.0 Required Option - - - - Supported
※4
Scalike
JDBC
2.4.2 - ※1 Required
※2
Supported Intuitive Runtime Supported
※1 Provides non-blocking API using postgresql-async or mysql-async
※2 A tool to generate table mappings from actual database schema is available
※3 Compile time SQL validation is available
※4 Runtime typechecking is available as experimental feature
31. Conclusion
● Web Fraemwork
○ All alternatives look good, but Play2 is not so bad
as well
○ For servlet container, Skinny Micro would be good
● Database Framework
○ There is no de-facto standard library currently
○ ScalikeJDBC looks good for us and almost users