Introducción a Ratpack
Toolkit para desarrollo web
Miguel de la Cruz
Ingeniero en Kaleidos Open Source
Antes de nada
¿Qué es Ratpack?
¿Qué es Ratpack?
- Toolkit para crear aplicaciones web
- Basado en Netty (Non-blocking I/O framework)
- Core implementado en Java
- Intenta hacer sencillo desarrollar aplicaciones simples, y no ser obstrusivo cuando éstas se compliquen
- La aplicación funciona en ~30 Mb
- No es una aplicación con Java Servlets
- Se despliega sin servidor de aplicaciones
- Live Reloading a través de spring-loaded
- Optimizado para Groovy y Java8
¿Cuándo usar Ratpack?
- No-framework
- Scripting
- Microservicios
¿Cuándo usar Grails?
- Persistencia out-of-the-box
- Modelo muy amplio con muchos endpoints
- Necesidad de Spring Security
Empezando a usar Ratpack
Grab
@Grab("io.ratpack:ratpack-groovy:0.9.2")
import static ratpack.groovy.Groovy.*
Cuatro líneas de DSL
ratpack {
handlers {
}
}
Live Coding
DSL Básico
¿Qué es un handler?
- Unidad básica de procesamiento en ratpack
- Interfaz a implementar
- Manipula un contexto, que proporciona acceso a request y response
Handler básico
ratpack{
handlers {
get {
render 'Hello World!'
}
}
}
Query params
get {
def name = request.queryParams.name
render "Hi $name!"
}
Path tokens
get('name/:name') {
def name = pathTokens.name
render "Hi $name, this time from PathTokens!"
}
Métodos HTTP
post('name/:name?') {
def name = pathTokens.name
render "Hi $name, this time from PathTokens and a POST endpoint!"
}
htmlBuilder
get('something') {
render htmlBuilder {
head {
title 'My website title'
}
body {
h1 'Hi stranger!'
p {
a href: 'http://github.com', "Let's visit GitHub!"
}
}
}
}
groovyTemplate
Handler
get {
render groovyTemplate([name: 'John Doe'], 'testTemplate.html')
}
Template
String que viene del modelo
${model.name}
Form
import ratpack.form.Form
post('myform') {
def form = parse Form
form.get('param')
form.file('fileName')
}
JSON
Podríamos usar un módulo de Guice
para Jackson
En su lugar, usaremos JsonOutput
y toJson
import static groovy.json.JsonOutput.toJson
get {
response.contentType 'application/json'
render toJson(['message': 'Long live to Json!'])
}
get('simpler') {
response.send 'application/json', toJson(['even': 'simpler'])
}
byMethod
handler('myendpoint') {
byMethod {
get {
response.send 'application/json', toJson(['method': 'GET'])
}
post {
response.send 'application/json', toJson(['method': 'POST'])
}
}
}
byContent
get {
byContent {
json {
render 'JSON'
}
plainText {
render 'TEXT'
}
html {
render 'HTML'
}
}
}
Prefix
prefix('api') {
get('end') {
render 'end'
}
get('point') {
render 'point'
}
}
Assets
ratpack {
handlers {
assets("public")
}
}
Total
Ya tenemos algo funcionando
Ratpack y gradle
Más allá del script
Podemos integrar nuestra aplicación con gradle
a través del plugin ratpack-groovy
Documentación
LazyBones al rescate
Herramienta de creación de proyectos a partir de plantillas
lazybones create [ratpack template] [ratpack version] [app name]
Project structure
src
|
+- ratpack
| |
| +- ratpack.groovy
| +- ratpack.properties
| +- public // Static assets in here
|
+- main
| |
| +- groovy
| |
| +- // App classes in here!
|
+- test
|
+- groovy
|
+- // Spock tests in here!
build.gradle
apply plugin: "ratpack-groovy"
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.ratpack:ratpack-gradle:0.9.2"
}
}
repositories {
jcenter()
maven { url "http://repo.springsource.org/repo" } // for springloaded
}
dependencies {
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
// SpringLoaded enables runtime hot reloading.
springloaded "org.springsource.springloaded:springloaded-core:1.1.1"
}
ratpack.properties
- Debe existir vacío.
- Podemos configurar
HandlerFactory
, el puerto... - No existe documentación
- Podemos basarnos en el JavaDoc de
LaunchConfig
ratpack.groovy
ratpack {
handlers {
}
}
Let's do this!
Inyección de dependencias con
Google Guice
Google Guice
- Jar:
ratpack-guice
- Dos usos principales
- Inyección de dependencias
- Modularización
Show me the code!
ScriptExecutionModule.groovy
class ScriptExecutionModule extends AbstractModule {
@Override
protected void configure() {
bind(ScriptExecutor).to(GroovyScriptExecutor)
}
}
GroovyScriptExecutor.groovy
class GroovyScriptExecutor implements ScriptExecutor {
ScriptResult execute(String scriptText) {
...
}
}
ratpack.groovy
ratpack {
modules {
register new ScriptExecutionModule()
}
post("execute") { ScriptExecutor scriptExecutor ->
def form = parse form()
def script = form.script
render scriptExecutor.execute(script)
}
}
Ratpack internals
Warning!
Hay poca documentación en "prosa".
Javadoc es tu amigo.
Handler
- Unidad de procesamiento en Ratpack
- El punto de entrada de la aplicación es un
Handler
- Interfaz a implementar
- Reciben un contexto
Ejemplo de Handler
import ratpack.handling.Handler
import ratpack.handling.Context
class TestHandler implements Handler {
void handle(Context context) {
context.render "Hello World!"
}
}
Se pueden encadenar
get 'chain', new FirstHandler()
class FirstHandler implements Handler {
void handle(Context context) {
println 'Soy el primer handler'
context.insert new SecondHandler()
}
}
class SecondHandler implements Handler {
void handle(Context context) {
println 'Soy el segundo handler'
context.render 'Response!'
}
}
// == Output GET /chain ==
// Soy el primer handler
// Soy el segundo handler
// [200] Response!
Si ningún handler envía un response...
El último handler es siempre uno interno que envía un 404
context.clientError 404
Context
- Proporciona acceso a
request
yresponse
- Los handlers reciben
context
y se lo pasan al siguiente - Podemos almacenar variables utilizando
registry
Ejemplo de uso de registry
class MyHandler implements Handler {
void handle(Context context) {
// get some data
Map myData = ['message': "hoy es ${new Date()}"]
// delegates on JSON
context.insert(registry(myData), new ToJson())
}
}
class ToJson implements Handler {
void handle(Context context) {
def myData = context.get(LinkedHashMap.class)
context.response.contentType 'application/json'
context.render toJson(myData)
}
}
Testing en Ratpack
Testing
- Ratpack no está ligado a ningún framework
- Se recomienda usar
spock
- El plugin de
gradle
prepara el proyecto para testing
Tipos de testing
- Unitario
UnitTest.invoke()
GroovyUnitTest.invoke()
- Funcional
ApplicationUnderTest
TestHttpClient
Ejemplo
Handler
class MyHandler implements Handler {
void handle(Context context) {
context.with {
def outputHeader = request.headers.get("input-value") + ":bar"
response.headers.set("output-value", outputHeader)
render "received: " + request.path
}
}
}
Ejemplo
Test
import static ratpack.groovy.test.GroovyUnitTest.invoke
def invocation = invoke(new MyHandler()) {
header "input-value", "foo"
uri "some/path"
}
assert invocation.rendered(String) == "received: some/path"
assert invocation.headers.get("output-value") == "foo:bar"
Desplegando Ratpack
Facts
- Las aplicaciones de Ratpack son autocontenidas
- No es necesario utilizar un servidor de apliaciones
- ... aunque es posible a través de un plugin de
gradle
- Consumo de memoria muy bajo
Tareas de gradle
# Genera la estructura de la aplicación
# en build/install/$applicationName
gradle installApp
# Comprime la aplicación en un fichero .zip
gradle distZip
# Comprime la aplicación en un fichero .tar
gradle distTar
Aplicación
Carpeta app
-
ratpack.groovy
&ratpack.properties
/templates
/public
Aplicación
Carpeta bin
Scripts de shell
y batch
que settean el classpath y ejecutan la aplicación
Aplicación
Carpeta lib
- Dependencias
"${applicationName}.jar"
Conclusiones
Ligero
Consume pocos recursos
Capaz
- HTML templates
- REST
- Inyección de dependencias
- Testeable
Toolkit != Framework
No toma decisiones por ti
Divertido
Q&A
Gracias :D
Introducción a Ratpack
By mgdelacroix
Introducción a Ratpack
- 1,235