http://www.ratpack.io
Dan Woods
#ratpack #learningratpack
•  Member of the Ratpack core team
•  Work at Netflix
•  Writing Learning Ratpack for O’Reilly
•  Follow me on Twitter: @danveloper
•  A full-stack, high throughput, non-blocking
web framework
•  Built entirely on Java 8
•  Specialized support for writing apps in Groovy
•  Groovy has come a long way over the last few
years…
•  Static compilation and (optional) compile time type
checking
•  Excellent language for writing concise DSLs
•  DSLs can be statically compiled!
Why Groovy?
•  Groovy’s three compilation modes give
applications a lot of flexibility
•  Parallels Java performance using Invoke Dynamic
or Static Compilation
•  Pick-and-choose static or dynamic, depending on
the use-case!
Why Groovy?
•  Requires Groovy 2.3.6+
•  Utilize advanced static compilation and type
checking features of Groovy, like @DelegatesTo
•  Allows you to define your application structure in a
ratpack.groovy file
Why Groovy?
@GrabResolver(name='netty', root='http://clinker.netty.io/
nexus/content/repositories/snapshots')!
@Grab('io.ratpack:ratpack-groovy:0.9.13-SNAPSHOT')!
!
import static ratpack.groovy.Groovy.ratpack!
!
ratpack {!
handlers {!
handler { !
response.send ”Hello World!"!
}!
}!
}!
Simple Groovy Script*
* @GrabResolver will not be required after 4.1.0-Beta4 is published;
* Ratpack 0.9.13 will be released on Feb 1, 2014
•  There are no plugins in Ratpack, instead the
framework provides functionality through modules
•  Modules are built in Guice*
•  DI is an abstraction in Ratpack, so even though the
framework uses Guice, you don’t have to
*	
  h$ps://github.com/google/guice	
  
•  A set of composable libraries for building
unopinionated, rich web applications
•  Pick-and-choose what aspects of the
framework you want
•  No lock-in to a single way of doing things
•  Emphasis on Performance and Efficiency in both applications
and development experience
•  Hot reloading is available during development time
•  Beautiful development-time error pages
•  Extreme emphasis on developer testing, especially functional
and integration
•  Support for mocking nearly all aspects of the framework
Example of a development-time error:
•  Convention over configuration taken too far
doesn’t let you wire things together
•  Ratpack makes wiring modules a “one-liner”, so
there’s not a lot of work to get new features
integrated
•  Out of the box support for Guice and Spring
(Spring Boot) DI
•  Gradle integration makes building robust
projects easy to do
•  Simple apps can be run entirely through
the Groovy command-line
buildscript {
repositories {
jcenter()
maven { url "http://oss.jfrog.org/oss-snapshot-local" }
maven { url "http://clinker.netty.io/nexus/content/repositories/snapshots" }
}
dependencies {
classpath 'io.ratpack:ratpack-gradle:0.9.13-SNAPSHOT'
}
}
apply plugin: 'io.ratpack.ratpack-java'
Simple Gradle Build Script*
* Ratpack 0.9.13 will be released on Feb 1, 2014
•  Any non-trivial application needs build and
packaging capabilities
•  The Ratpack Gradle plugin provides all the
fixtures to support building web
application projects
•  Ratpack is built on Netty, which provides
the infrastructure for highly performant,
non-blocking networking
•  Netty is an extremely mature, super low-level
networking library
•  Excellent documentation, very involved
community
•  Heavy emphasis on high throughput and
performance
•  Netty provides the infrastructure for non-
blocking networking, but doesn’t help
much in the way of web application
structure
•  Provides an asynchronous API for working
with network data (including HTTP)
•  Computers “think” very good in asynchronous
terms; humans do not…
•  Without app structure, programming toward this
paradigm is difficult
•  Ratpack ensures the most performant structures of
Netty are being utilized, while providing a sensible
app structure and programming model
•  Ratpack provides applications with a Netty-based, non-
blocking HTTP client
•  Can be used to integrate with external RESTful services
•  Utilizes the same event loop as the server, so resources
are appropriately utilized
•  Provides a robust API for programmatically crafting
requests
Above all else…
Ratpack is your
GATEWAY DRUG
to non-blocking
•  The JVM doesn’t have any concept of continuations, so
the only option we have is asynchronous APIs
•  Async APIs allow callers to provide a completion
handler (or callback), which is to be invoked when some
processing has finished
•  There is no temporal relationship between the caller
and the invocation of the callback
handler { req, res ->!
... (1) do some work ...!
!
async {!
... (2) do some async work ...!
}!
async {!
... (3) do some more async ...!
}!
!
... (4) send response ...!
}!
(1)  – Definitely finishes first
(2)  – May finish before or after (3)
and (4)
(3)  – May finish before or after (2) or
(4)
(4)  – May finish before or after (2) or
(3)
Async APIs create non-determinism in control flow
•  The temporal disconnect creates non-determinism
in request processing
•  This is a big problem for web applications, because
they demand a deterministic control flow
•  Ratpack provides the concept of an Execution,
which creates determinism in asynchronous
processing
handler { req, res ->!
... (1) do some work ...!
!
async {!
... (3) do some async work ...!
}!
async {!
... (4) do some more async ...!
}!
!
... (2) send response ...!
}!
(1) – Definitely finishes first
(3) – Definitely finishes third
(4) – Definitely finishes fourth
(2) – Definitely finishes second
Ratpack creates a deterministic control flow
•  Through Ratpack’s promise API, the Execution
is able to schedule async segments to be
invoked after the handler code has finished
•  Promise API ensures that developers can work
with asynchronous processing in a sensible
way
•  In non-blocking, it is of paramount importance
to not block the thread
•  Since a single thread is handling processing
for many clients, blocking one blocks all
•  Need to adopt libraries that are non-blocking
or provide async APIs
•  This is not always practical…
•  Not all interfaces are able to be non-blocking or
asynchronous
•  Most non-blocking frameworks force you to be either
entirely async or wholesale define your handlers as
blocking
•  This is limiting and makes it difficult to work with legacy
APIs or those not crafted for non-blocking work
•  Ratpack gives you a mechanism to define blocking
execution segments in your handler code
handler(r -> (ctx) -> {
ModelDAO dao = ctx.get(ModelDAO.class);
ctx.blocking(() ->
dao.load(ctx.getPathTokens().get("id")))
.then(model -> {
... do some work with the data ...
ctx.render(model);
});
})
Handler with blocking operation
•  Blocking operations are scheduled to an I/O
bound thread pool
•  Once the blocking operation is completed,
the data is then returned to the request taking
thread, where processing can finish
•  Blocking operations are invoked when they
are subscribed to in the request-taking thread
...
ctx.blocking(() -> {
... do some blocking io ...
return result;
}).then(result -> {
... subscribe to the blocking promise ...
... process in the request-taking thread ...
})
...
Blocking with a subscription
•  Data is being delivered to web consumers in
an increasingly real time way
•  Web applications must be able to support
streaming protocols like SSE and WebSockets
•  Ratpack has built-in fixtures that make it easy
to develop real-time web applications
•  Because of its non-blocking nature, Ratpack can
support a high volume of concurrent real-time
streams
•  Valuable in app-to-app communication too, where
a consumer wants to be reactively informed about
some data
•  Ratpack’s HTTP client also supports reading
streams of data from external producers, making
stream processing a great integration
•  Ratpack applications are defined through a
handler chain
•  Handler chain is a programmatic construct
for managing the flow of request data
•  Handlers can be bound to request path
routes and HTTP verbs
import static ratpack.groovy.Groovy.ratpack!
!
ratpack {!
handlers {!
get {!
response.send "I'm the default route!"!
}!
get("route1") {!
response.send "I'm in route1"!
}!
get("route2/:param") {!
response.send "I'm in route2 and received param: ${pathTokens.param}"!
}!
}!
}!
Handler chain in a Ratpack Script-backed app
RatpackServer.start(b -> b

.config(ServerConfig.noBaseDir())

.handlers(chain -> chain

.get(ctx -> ctx.getResponse()

.send("I'm in the default route!"))

!
.get("route1", (ctx) -> ctx.getResponse()

.send("I'm in route1!"))

!
.get("route2/:param", (ctx) -> ctx.getResponse()

.send(String

.format(” received param: %s",

ctx.getPathTokens().get("param"))))

)

);"
Handler chain in using Java 8 APIs
•  Ratpack applications are defined through a
handler chain
•  Handler chain is a programmatic construct
for managing the flow of request data
•  Handlers can be bound to request path
routes and HTTP verbs
handlers {!
get { ... }!
get("route") { ... }!
!
post { ... }!
post("route") { ... }!
!
put { ... }!
put("route") { ... }!
!
delete { ... }!
delete("route") { ... }!
!
patch { ... }!
patch("route") { ... }!
}!
Semantic handler API for binding to HTTP verbs and routes
•  Handlers can be nested within a route…
handlers {

prefix("api") { ModelDAO dao ->

get {

blocking { dao.getAll() }.

then { models -> render JsonOutput.toJson(models) }

}

post {

Model model = parse(fromJson(Model))

blocking { dao.save(model) }.

then { m -> render m }

}

put(":id") {

blocking { dao.load(pathTokens.id) }.

map { model -> model.merge(parse(fromJson(Model))) }.

blockingMap { model -> dao.save(model) }.

then { model -> render model }

}

}

}!
•  There’s a special handler type for serving
static assets from the app’s baseDir!
•  Static assets must be defined as the last
handler in the chain
•  Can be scoped to routes
•  Use the assets handler to serve static content
handlers {

prefix("api") {

get {

response.send "some API data"

}

}

assets("public", "index.html”)

}!
•  You can also use a handler with byMethod to perform common processing
within a route…
handlers {

handler("api") { ModelDAO dao ->

dao.beginTransaction()

byMethod {

get {}

post {}

put {}

delete {}

}

dao.endTransaction()

}!
}!
•  Can discriminate on content type, allowing you to build HyperMedia APIs…
handlers {

handler {

byContent {

json {

response.send(toJson([msg: "regular json"]))

}

xml {

response.send(...)

}

type("application/vnd.app.org+json;v=1") {

response.send(toJson([newmsg: "hypermedia json"]))

}

}

}

}!
•  Handlers define the edge of your application
•  In Servlet API terms, handlers can be thought
of as a marriage between filters and servlets
•  Allows request introspection and
programmatic injection of handler chain
•  This allows handlers to be constructed and dependency injected, etc…
class UserHandler implements Handler {



private final String message



UserHandler(String message) {

this.message = message

}



@Override

void handle(Context context) !
!throws Exception {

context.response.send(message)

}

}!
ratpack {

bindings {

bindInstance(new UserHandler("user handler"))

}

handlers {

handler { UserHandler userHandler ->

if (request!
.headers.contains("X-Routing-Header")) {

def routingHeader = request!
.headers.get("X-Routing-Header")

if (routingHeader == "user") {

insert(userHandler)

}

}

next()

}

get {

response.send "default system handler"

}

}

}!
New	
  Handler	
  is	
  
programma1cally	
  inserted	
  
into	
  the	
  processing	
  chain	
  
•  Dependency injection is an abstraction in
Ratpack, through the concept of a Registry
•  Components are bound to, and resolvable
from, a Registry instance
•  Registries can be backed in a DI framework
•  Out of the box support for Guice and Spring
Boot
•  Registries can be inherited, allowing
components to be resolved in a cascading
manner
•  Every request context gets a registry that
components can be extracted from
•  In a Groovy script that uses closures as
handlers, the variable arguments to that
closure are “injected” from the registry
•  In Java 8, they are able to be resolved from
the request context object
•  You don’t need to use a DI framework to get injection support, you can build
your own registry from objects you construct…
public static void main(String[] args) throws Exception {

Registry registry = Registries.registry()

.add(new ModelDAO()).add(new DB()).build();



RatpackServer.start(spec -> spec

.config(ServerConfig.noBaseDir())

.handlers(chain -> {

chain.register(registry);

chain.handler(":id", ctx -> {

ModelDAO dao = ctx.get(ModelDAO.class);

ctx.blocking(() ->

dao.load(ctx.getPathTokens().get("id")))

.then(ctx::render);

});

})

);

}!
•  Variables arguments to Groovy closure handlers are resolved from the
registry
def myRegistry = Registries.registry()

.add(new ModelDAO())

.build()



ratpack {

handlers {

register(myRegistry)



prefix("api") {

get(":id") { ModelDAO dao ->

render dao.load(pathTokens.id)

}

}

assets("public", "index.html”)

}

}!
•  In Groovy, you get a bindings block, which you can use to bind components
to the Registry. With Guice, annotations can be used to Inject
class UserHandler implements Handler {



private final ModelDAO dao



@javax.inject.Inject!
UserHandler(ModelDAO dao) {

this.message = message

}



@Override

void handle(Context ctx) !
!throws Exception {

ctx.blocking {!
dao.getAll()!
} then { ctx.render(it) }

}

}!
ratpack {

bindings {

binder { b ->

b.bind(ModelDAO).in(Scopes.SINGLETON)

b.bind(UserHandler).in(Scopes.SINGLETON)

}

}!
handlers {

handler { UserHandler userHandler ->

if (request!
.headers.contains("X-Routing-Header")) {

def routingHeader = request!
.headers.get("X-Routing-Header")

if (routingHeader == "user") {

insert(userHandler)

}

}

next()

}

get {

response.send "default system handler"

}

}

}!
Can	
  get	
  a	
  handle	
  on	
  a	
  Guice	
  
binder	
  to	
  perform	
  
annota1on-­‐based	
  Injec1ng	
  
•  Likewise, a Guice Module can be “added” to the registry…
ratpack {

bindings {!
// Any Guice module can be added this way!
// this is how Ratpack modules are"
// introduced... "
add(new SqlModule())

}!
handlers {

...!
}

}!
•  Spring application context can be used to
back a registry using the
ratpack.spring.Spring class
h>p://www.ratpack.io/manual/0.9.13/api/ratpack/spring/Spring.html	
  
	
  
•  Like handlers, registries can be
programmatically registered into the
handler chain based on request data
•  Can allow your app to resolve components
specific to the context of a request
•  Likewise, a Guice Module can be “added” to the registry…
def baseRegistry = Registries.registry()

.add(new ModelDAO("jdbc:mysql://default"))

.build()



def cust1Registry = Registries.registry()

.add(new ModelDAO("jdbc:mysql://cust1"))

.build()



ratpack {

bindings {

bindInstance(new DefaultDevelopmentErrorHandler())

}

handlers {

handler {

next(get(PublicAddress).getAddress(it).host == "cust1" ? cust1Registry : baseRegistry)

}

prefix("api") {

get(":id") { ModelDAO dao ->

render blocking { dao.load(pathTokens.id) }

}

}

assets("public", "index.html”)

}

}!
•  Including framework modules in your
Gradle based project is really easy
•  Can utilize helper methods from the
Ratpack Gradle plugin to include named
modules
•  Allows framework versions to stay in sync
•  The Ratpack Gradle plugin provides the ratpack.dependency() helper
...!
!
dependencies {

compile ratpack.dependency("jackson”)

compile ratpack.dependency(”rxjava”)!
compile ratpack.dependency(”codahale-metrics”)!
testCompile ratpack.dependency(”remote-test”) !
}!
!
...!
•  Including framework modules in your
Gradle based project is really easy
•  Can utilize helper methods from the
Ratpack Gradle plugin to include named
modules
•  Allows framework versions to stay in sync
•  Static fixtures for mapping a multitude of external and environmental configuration
sources to POJOs
Configuration Module: ratpack-config
// build.gradle"
dependencies {!
...

compile ratpack.dependency(”config”)!
...

}!
import ratpack.config.*;!
!
ConfigurationData configData =
Configurations.config()

.yaml(Main.class.getResource("/app.yml"))

.json(Main.class.getResource("/app.json"))

.props("/etc/app/file.properties")

.sysProps()

.env()

.build();!
!
ServerConfig config = configData!
.get("/server", ServerConfig.class);



RatpackServer.start(spec -> spec

.config(config)

.handlers(...)

);!
// classpath:/app.yml"
server:!
port: 8080!
!
myAppStuff:!
anyConfigData: 1234!
•  Environment-derivable configuration
follows the principle of the Twelve Factor
App
Great Support for building MICROSERVICES!!
•  NetflixOSS Hystrix support, via the ratpack-
hystrix module
•  Calls to remote services can be made fault
tolerant
•  Ability to stream Hystrix metrics to the Hystrix
Dashboard
Great Support for building MICROSERVICES!!
•  The ratpack-hikari module uses HikariCP
to create a super fast pooled SQL DataSource
•  Can be used in conjunction with Groovy SQL
to query databases
•  Configurable using the fixtures from the
ratpack-config module
Great Support for DATABASES!!
•  The ratpack-jackson module provides
request data parsing and object rendering
from and to JSON
•  Data can be worked with in free-form nodes,
or bound to command objects
•  Arbitrary models can be rendered as JSON
using simply context.render(obj)!
Great Support for DATA BINDING!!
•  Ratpack’s Promise API is an implementation of
Reactive Streams Specification
•  The ratpack-rxjava module provides a
bridge between a Ratpack Promise and an
RxJava Observable
•  The ratpack-reactor module allows data
to be processed using Project Reactor
Great Support for REACTIVE PROGRAMMING!!
•  View templates can be rendered through a variety
of means
•  Support for server-side templating with
Handlebars, Thymeleaf, Groovy Templates, and
Groovy Markup
•  Ongoing work to integrate @davydotcom’s asset-
pipeline, which will give robust support for all types
of static content
Great Support for FULL-STACK FEATURES!!
•  Ratpack has been built from the ground-up with
testing considered at every turn
•  Even more-so – considering testing from the
perspective of the developer
•  The concept of the Registry gives the framework
control over components
•  Makes it easy to provide fixtures for mocking and
stubbing data
•  The EmbeddedApp class from the ratpack-
test module supports functional and
integration testing
•  Can be used to test an application module
or a subset of handlers and functionality
•  Can be used outside of Ratpack too!
•  Spock is the choice framework, though
there’s no strict integration there
•  Functional tests are easy to bootstrap and
the TestHttpClient helper makes it easy to
programmatically craft test calls
•  Great resource for seeing Ratpack’s testing
in action is the example-books project
•  Rus Hart keeps this up to date with changes
to the framework.
•  https://github.com/ratpack/example-books
Twitter people to follow:!
!
•  @ldaley!
•  @rus_hart!
•  @varzof!
•  @Lspacewalker!
•  @marcinerdmann!
•  @ratpackweb!
•  @davydotcom!
•  @johnrengelman!
•  @rfletcherEW!
•  @beckje01!

Ratpack Web Framework

  • 1.
  • 2.
    •  Member ofthe Ratpack core team •  Work at Netflix •  Writing Learning Ratpack for O’Reilly •  Follow me on Twitter: @danveloper
  • 3.
    •  A full-stack,high throughput, non-blocking web framework •  Built entirely on Java 8 •  Specialized support for writing apps in Groovy
  • 4.
    •  Groovy hascome a long way over the last few years… •  Static compilation and (optional) compile time type checking •  Excellent language for writing concise DSLs •  DSLs can be statically compiled! Why Groovy?
  • 5.
    •  Groovy’s threecompilation modes give applications a lot of flexibility •  Parallels Java performance using Invoke Dynamic or Static Compilation •  Pick-and-choose static or dynamic, depending on the use-case! Why Groovy?
  • 6.
    •  Requires Groovy2.3.6+ •  Utilize advanced static compilation and type checking features of Groovy, like @DelegatesTo •  Allows you to define your application structure in a ratpack.groovy file Why Groovy?
  • 7.
    @GrabResolver(name='netty', root='http://clinker.netty.io/ nexus/content/repositories/snapshots')! @Grab('io.ratpack:ratpack-groovy:0.9.13-SNAPSHOT')! ! import staticratpack.groovy.Groovy.ratpack! ! ratpack {! handlers {! handler { ! response.send ”Hello World!"! }! }! }! Simple Groovy Script* * @GrabResolver will not be required after 4.1.0-Beta4 is published; * Ratpack 0.9.13 will be released on Feb 1, 2014
  • 8.
    •  There areno plugins in Ratpack, instead the framework provides functionality through modules •  Modules are built in Guice* •  DI is an abstraction in Ratpack, so even though the framework uses Guice, you don’t have to *  h$ps://github.com/google/guice  
  • 9.
    •  A setof composable libraries for building unopinionated, rich web applications •  Pick-and-choose what aspects of the framework you want •  No lock-in to a single way of doing things
  • 10.
    •  Emphasis onPerformance and Efficiency in both applications and development experience •  Hot reloading is available during development time •  Beautiful development-time error pages •  Extreme emphasis on developer testing, especially functional and integration •  Support for mocking nearly all aspects of the framework
  • 11.
    Example of adevelopment-time error:
  • 12.
    •  Convention overconfiguration taken too far doesn’t let you wire things together •  Ratpack makes wiring modules a “one-liner”, so there’s not a lot of work to get new features integrated •  Out of the box support for Guice and Spring (Spring Boot) DI
  • 13.
    •  Gradle integrationmakes building robust projects easy to do •  Simple apps can be run entirely through the Groovy command-line
  • 14.
    buildscript { repositories { jcenter() maven{ url "http://oss.jfrog.org/oss-snapshot-local" } maven { url "http://clinker.netty.io/nexus/content/repositories/snapshots" } } dependencies { classpath 'io.ratpack:ratpack-gradle:0.9.13-SNAPSHOT' } } apply plugin: 'io.ratpack.ratpack-java' Simple Gradle Build Script* * Ratpack 0.9.13 will be released on Feb 1, 2014
  • 15.
    •  Any non-trivialapplication needs build and packaging capabilities •  The Ratpack Gradle plugin provides all the fixtures to support building web application projects
  • 16.
    •  Ratpack isbuilt on Netty, which provides the infrastructure for highly performant, non-blocking networking
  • 17.
    •  Netty isan extremely mature, super low-level networking library •  Excellent documentation, very involved community •  Heavy emphasis on high throughput and performance
  • 18.
    •  Netty providesthe infrastructure for non- blocking networking, but doesn’t help much in the way of web application structure •  Provides an asynchronous API for working with network data (including HTTP)
  • 19.
    •  Computers “think”very good in asynchronous terms; humans do not… •  Without app structure, programming toward this paradigm is difficult •  Ratpack ensures the most performant structures of Netty are being utilized, while providing a sensible app structure and programming model
  • 20.
    •  Ratpack providesapplications with a Netty-based, non- blocking HTTP client •  Can be used to integrate with external RESTful services •  Utilizes the same event loop as the server, so resources are appropriately utilized •  Provides a robust API for programmatically crafting requests
  • 21.
    Above all else… Ratpackis your GATEWAY DRUG to non-blocking
  • 23.
    •  The JVMdoesn’t have any concept of continuations, so the only option we have is asynchronous APIs •  Async APIs allow callers to provide a completion handler (or callback), which is to be invoked when some processing has finished •  There is no temporal relationship between the caller and the invocation of the callback
  • 24.
    handler { req,res ->! ... (1) do some work ...! ! async {! ... (2) do some async work ...! }! async {! ... (3) do some more async ...! }! ! ... (4) send response ...! }! (1)  – Definitely finishes first (2)  – May finish before or after (3) and (4) (3)  – May finish before or after (2) or (4) (4)  – May finish before or after (2) or (3) Async APIs create non-determinism in control flow
  • 25.
    •  The temporaldisconnect creates non-determinism in request processing •  This is a big problem for web applications, because they demand a deterministic control flow •  Ratpack provides the concept of an Execution, which creates determinism in asynchronous processing
  • 26.
    handler { req,res ->! ... (1) do some work ...! ! async {! ... (3) do some async work ...! }! async {! ... (4) do some more async ...! }! ! ... (2) send response ...! }! (1) – Definitely finishes first (3) – Definitely finishes third (4) – Definitely finishes fourth (2) – Definitely finishes second Ratpack creates a deterministic control flow
  • 27.
    •  Through Ratpack’spromise API, the Execution is able to schedule async segments to be invoked after the handler code has finished •  Promise API ensures that developers can work with asynchronous processing in a sensible way
  • 28.
    •  In non-blocking,it is of paramount importance to not block the thread •  Since a single thread is handling processing for many clients, blocking one blocks all •  Need to adopt libraries that are non-blocking or provide async APIs •  This is not always practical…
  • 29.
    •  Not allinterfaces are able to be non-blocking or asynchronous •  Most non-blocking frameworks force you to be either entirely async or wholesale define your handlers as blocking •  This is limiting and makes it difficult to work with legacy APIs or those not crafted for non-blocking work •  Ratpack gives you a mechanism to define blocking execution segments in your handler code
  • 30.
    handler(r -> (ctx)-> { ModelDAO dao = ctx.get(ModelDAO.class); ctx.blocking(() -> dao.load(ctx.getPathTokens().get("id"))) .then(model -> { ... do some work with the data ... ctx.render(model); }); }) Handler with blocking operation
  • 31.
    •  Blocking operationsare scheduled to an I/O bound thread pool •  Once the blocking operation is completed, the data is then returned to the request taking thread, where processing can finish •  Blocking operations are invoked when they are subscribed to in the request-taking thread
  • 32.
    ... ctx.blocking(() -> { ...do some blocking io ... return result; }).then(result -> { ... subscribe to the blocking promise ... ... process in the request-taking thread ... }) ... Blocking with a subscription
  • 33.
    •  Data isbeing delivered to web consumers in an increasingly real time way •  Web applications must be able to support streaming protocols like SSE and WebSockets •  Ratpack has built-in fixtures that make it easy to develop real-time web applications
  • 34.
    •  Because ofits non-blocking nature, Ratpack can support a high volume of concurrent real-time streams •  Valuable in app-to-app communication too, where a consumer wants to be reactively informed about some data •  Ratpack’s HTTP client also supports reading streams of data from external producers, making stream processing a great integration
  • 36.
    •  Ratpack applicationsare defined through a handler chain •  Handler chain is a programmatic construct for managing the flow of request data •  Handlers can be bound to request path routes and HTTP verbs
  • 37.
    import static ratpack.groovy.Groovy.ratpack! ! ratpack{! handlers {! get {! response.send "I'm the default route!"! }! get("route1") {! response.send "I'm in route1"! }! get("route2/:param") {! response.send "I'm in route2 and received param: ${pathTokens.param}"! }! }! }! Handler chain in a Ratpack Script-backed app
  • 38.
    RatpackServer.start(b -> b
 .config(ServerConfig.noBaseDir())
 .handlers(chain-> chain
 .get(ctx -> ctx.getResponse()
 .send("I'm in the default route!"))
 ! .get("route1", (ctx) -> ctx.getResponse()
 .send("I'm in route1!"))
 ! .get("route2/:param", (ctx) -> ctx.getResponse()
 .send(String
 .format(” received param: %s",
 ctx.getPathTokens().get("param"))))
 )
 );" Handler chain in using Java 8 APIs
  • 39.
    •  Ratpack applicationsare defined through a handler chain •  Handler chain is a programmatic construct for managing the flow of request data •  Handlers can be bound to request path routes and HTTP verbs
  • 40.
    handlers {! get {... }! get("route") { ... }! ! post { ... }! post("route") { ... }! ! put { ... }! put("route") { ... }! ! delete { ... }! delete("route") { ... }! ! patch { ... }! patch("route") { ... }! }! Semantic handler API for binding to HTTP verbs and routes
  • 41.
    •  Handlers canbe nested within a route… handlers {
 prefix("api") { ModelDAO dao ->
 get {
 blocking { dao.getAll() }.
 then { models -> render JsonOutput.toJson(models) }
 }
 post {
 Model model = parse(fromJson(Model))
 blocking { dao.save(model) }.
 then { m -> render m }
 }
 put(":id") {
 blocking { dao.load(pathTokens.id) }.
 map { model -> model.merge(parse(fromJson(Model))) }.
 blockingMap { model -> dao.save(model) }.
 then { model -> render model }
 }
 }
 }!
  • 42.
    •  There’s aspecial handler type for serving static assets from the app’s baseDir! •  Static assets must be defined as the last handler in the chain •  Can be scoped to routes
  • 43.
    •  Use theassets handler to serve static content handlers {
 prefix("api") {
 get {
 response.send "some API data"
 }
 }
 assets("public", "index.html”)
 }!
  • 44.
    •  You canalso use a handler with byMethod to perform common processing within a route… handlers {
 handler("api") { ModelDAO dao ->
 dao.beginTransaction()
 byMethod {
 get {}
 post {}
 put {}
 delete {}
 }
 dao.endTransaction()
 }! }!
  • 45.
    •  Can discriminateon content type, allowing you to build HyperMedia APIs… handlers {
 handler {
 byContent {
 json {
 response.send(toJson([msg: "regular json"]))
 }
 xml {
 response.send(...)
 }
 type("application/vnd.app.org+json;v=1") {
 response.send(toJson([newmsg: "hypermedia json"]))
 }
 }
 }
 }!
  • 46.
    •  Handlers definethe edge of your application •  In Servlet API terms, handlers can be thought of as a marriage between filters and servlets •  Allows request introspection and programmatic injection of handler chain
  • 47.
    •  This allowshandlers to be constructed and dependency injected, etc… class UserHandler implements Handler {
 
 private final String message
 
 UserHandler(String message) {
 this.message = message
 }
 
 @Override
 void handle(Context context) ! !throws Exception {
 context.response.send(message)
 }
 }! ratpack {
 bindings {
 bindInstance(new UserHandler("user handler"))
 }
 handlers {
 handler { UserHandler userHandler ->
 if (request! .headers.contains("X-Routing-Header")) {
 def routingHeader = request! .headers.get("X-Routing-Header")
 if (routingHeader == "user") {
 insert(userHandler)
 }
 }
 next()
 }
 get {
 response.send "default system handler"
 }
 }
 }! New  Handler  is   programma1cally  inserted   into  the  processing  chain  
  • 49.
    •  Dependency injectionis an abstraction in Ratpack, through the concept of a Registry •  Components are bound to, and resolvable from, a Registry instance •  Registries can be backed in a DI framework
  • 50.
    •  Out ofthe box support for Guice and Spring Boot •  Registries can be inherited, allowing components to be resolved in a cascading manner •  Every request context gets a registry that components can be extracted from
  • 51.
    •  In aGroovy script that uses closures as handlers, the variable arguments to that closure are “injected” from the registry •  In Java 8, they are able to be resolved from the request context object
  • 52.
    •  You don’tneed to use a DI framework to get injection support, you can build your own registry from objects you construct… public static void main(String[] args) throws Exception {
 Registry registry = Registries.registry()
 .add(new ModelDAO()).add(new DB()).build();
 
 RatpackServer.start(spec -> spec
 .config(ServerConfig.noBaseDir())
 .handlers(chain -> {
 chain.register(registry);
 chain.handler(":id", ctx -> {
 ModelDAO dao = ctx.get(ModelDAO.class);
 ctx.blocking(() ->
 dao.load(ctx.getPathTokens().get("id")))
 .then(ctx::render);
 });
 })
 );
 }!
  • 53.
    •  Variables argumentsto Groovy closure handlers are resolved from the registry def myRegistry = Registries.registry()
 .add(new ModelDAO())
 .build()
 
 ratpack {
 handlers {
 register(myRegistry)
 
 prefix("api") {
 get(":id") { ModelDAO dao ->
 render dao.load(pathTokens.id)
 }
 }
 assets("public", "index.html”)
 }
 }!
  • 54.
    •  In Groovy,you get a bindings block, which you can use to bind components to the Registry. With Guice, annotations can be used to Inject class UserHandler implements Handler {
 
 private final ModelDAO dao
 
 @javax.inject.Inject! UserHandler(ModelDAO dao) {
 this.message = message
 }
 
 @Override
 void handle(Context ctx) ! !throws Exception {
 ctx.blocking {! dao.getAll()! } then { ctx.render(it) }
 }
 }! ratpack {
 bindings {
 binder { b ->
 b.bind(ModelDAO).in(Scopes.SINGLETON)
 b.bind(UserHandler).in(Scopes.SINGLETON)
 }
 }! handlers {
 handler { UserHandler userHandler ->
 if (request! .headers.contains("X-Routing-Header")) {
 def routingHeader = request! .headers.get("X-Routing-Header")
 if (routingHeader == "user") {
 insert(userHandler)
 }
 }
 next()
 }
 get {
 response.send "default system handler"
 }
 }
 }! Can  get  a  handle  on  a  Guice   binder  to  perform   annota1on-­‐based  Injec1ng  
  • 55.
    •  Likewise, aGuice Module can be “added” to the registry… ratpack {
 bindings {! // Any Guice module can be added this way! // this is how Ratpack modules are" // introduced... " add(new SqlModule())
 }! handlers {
 ...! }
 }!
  • 56.
    •  Spring applicationcontext can be used to back a registry using the ratpack.spring.Spring class h>p://www.ratpack.io/manual/0.9.13/api/ratpack/spring/Spring.html    
  • 57.
    •  Like handlers,registries can be programmatically registered into the handler chain based on request data •  Can allow your app to resolve components specific to the context of a request
  • 58.
    •  Likewise, aGuice Module can be “added” to the registry… def baseRegistry = Registries.registry()
 .add(new ModelDAO("jdbc:mysql://default"))
 .build()
 
 def cust1Registry = Registries.registry()
 .add(new ModelDAO("jdbc:mysql://cust1"))
 .build()
 
 ratpack {
 bindings {
 bindInstance(new DefaultDevelopmentErrorHandler())
 }
 handlers {
 handler {
 next(get(PublicAddress).getAddress(it).host == "cust1" ? cust1Registry : baseRegistry)
 }
 prefix("api") {
 get(":id") { ModelDAO dao ->
 render blocking { dao.load(pathTokens.id) }
 }
 }
 assets("public", "index.html”)
 }
 }!
  • 60.
    •  Including frameworkmodules in your Gradle based project is really easy •  Can utilize helper methods from the Ratpack Gradle plugin to include named modules •  Allows framework versions to stay in sync
  • 61.
    •  The RatpackGradle plugin provides the ratpack.dependency() helper ...! ! dependencies {
 compile ratpack.dependency("jackson”)
 compile ratpack.dependency(”rxjava”)! compile ratpack.dependency(”codahale-metrics”)! testCompile ratpack.dependency(”remote-test”) ! }! ! ...!
  • 62.
    •  Including frameworkmodules in your Gradle based project is really easy •  Can utilize helper methods from the Ratpack Gradle plugin to include named modules •  Allows framework versions to stay in sync
  • 63.
    •  Static fixturesfor mapping a multitude of external and environmental configuration sources to POJOs Configuration Module: ratpack-config // build.gradle" dependencies {! ...
 compile ratpack.dependency(”config”)! ...
 }! import ratpack.config.*;! ! ConfigurationData configData = Configurations.config()
 .yaml(Main.class.getResource("/app.yml"))
 .json(Main.class.getResource("/app.json"))
 .props("/etc/app/file.properties")
 .sysProps()
 .env()
 .build();! ! ServerConfig config = configData! .get("/server", ServerConfig.class);
 
 RatpackServer.start(spec -> spec
 .config(config)
 .handlers(...)
 );! // classpath:/app.yml" server:! port: 8080! ! myAppStuff:! anyConfigData: 1234!
  • 64.
    •  Environment-derivable configuration followsthe principle of the Twelve Factor App Great Support for building MICROSERVICES!!
  • 65.
    •  NetflixOSS Hystrixsupport, via the ratpack- hystrix module •  Calls to remote services can be made fault tolerant •  Ability to stream Hystrix metrics to the Hystrix Dashboard Great Support for building MICROSERVICES!!
  • 66.
    •  The ratpack-hikarimodule uses HikariCP to create a super fast pooled SQL DataSource •  Can be used in conjunction with Groovy SQL to query databases •  Configurable using the fixtures from the ratpack-config module Great Support for DATABASES!!
  • 67.
    •  The ratpack-jacksonmodule provides request data parsing and object rendering from and to JSON •  Data can be worked with in free-form nodes, or bound to command objects •  Arbitrary models can be rendered as JSON using simply context.render(obj)! Great Support for DATA BINDING!!
  • 68.
    •  Ratpack’s PromiseAPI is an implementation of Reactive Streams Specification •  The ratpack-rxjava module provides a bridge between a Ratpack Promise and an RxJava Observable •  The ratpack-reactor module allows data to be processed using Project Reactor Great Support for REACTIVE PROGRAMMING!!
  • 69.
    •  View templatescan be rendered through a variety of means •  Support for server-side templating with Handlebars, Thymeleaf, Groovy Templates, and Groovy Markup •  Ongoing work to integrate @davydotcom’s asset- pipeline, which will give robust support for all types of static content Great Support for FULL-STACK FEATURES!!
  • 71.
    •  Ratpack hasbeen built from the ground-up with testing considered at every turn •  Even more-so – considering testing from the perspective of the developer •  The concept of the Registry gives the framework control over components •  Makes it easy to provide fixtures for mocking and stubbing data
  • 72.
    •  The EmbeddedAppclass from the ratpack- test module supports functional and integration testing •  Can be used to test an application module or a subset of handlers and functionality •  Can be used outside of Ratpack too!
  • 73.
    •  Spock isthe choice framework, though there’s no strict integration there •  Functional tests are easy to bootstrap and the TestHttpClient helper makes it easy to programmatically craft test calls
  • 74.
    •  Great resourcefor seeing Ratpack’s testing in action is the example-books project •  Rus Hart keeps this up to date with changes to the framework. •  https://github.com/ratpack/example-books
  • 75.
    Twitter people tofollow:! ! •  @ldaley! •  @rus_hart! •  @varzof! •  @Lspacewalker! •  @marcinerdmann! •  @ratpackweb! •  @davydotcom! •  @johnrengelman! •  @rfletcherEW! •  @beckje01!