Ratpack avec Groovy

1. Vue d'ensemble

Ratpack est un ensemble de bibliothèques Java légères pour créer des applications HTTP évolutives avec des fonctionnalités réactives, asynchrones et non bloquantes.

De plus, Ratpack fournit également une intégration avec des technologies et des frameworks tels que Google Guice, Spring Boot, RxJava et Hystrix.

Dans ce tutoriel, nous allons explorer comment utiliser Ratpack avec Groovy .

2. Pourquoi Groovy?

Groovy est un langage puissant et dynamique qui s'exécute dans la JVM.

Par conséquent, Groovy rend les scripts et les langages spécifiques au domaine vraiment faciles. Avec Ratpack, cela permet un développement rapide d'applications Web.

Ratpack permet une intégration facile avec Groovy via les bibliothèques ratpack-groovy et ratpack -groovy-test .

3. Application Ratpack utilisant Groovy Script

Les API Ratpack Groovy sont construites en Java afin de s'intégrer facilement aux applications Java et Groovy. Ils sont disponibles dans le package ratpack.groovy .

En fait, en combinaison avec les capacités de script de Groovy et la gestion des dépendances de Grape, nous pouvons rapidement créer une application Web alimentée par Ratpack en quelques lignes:

@Grab('io.ratpack:ratpack-groovy:1.6.1') import static ratpack.groovy.Groovy.ratpack ratpack { handlers { get { render 'Hello World from Ratpack with Groovy!!' } } }

Il s'agit de notre premier gestionnaire, qui gère une requête GET. Tout ce que nous avions à faire était d'ajouter un DSL de base pour activer le serveur Ratpack.

Exécutons maintenant ceci en tant que script Groovy pour démarrer l'application. Par défaut, l'application sera disponible sur // localhost: 5050 :

$ curl -s localhost:5050 Hello World from Ratpack with Groovy!!

Nous pouvons également configurer le port en utilisant ServerConfig :

ratpack { serverConfig { port(5056) } }

Ratpack fournit également une fonction de rechargement à chaud , ce qui signifie que nous pouvons modifier Ratpack.groovy , puis voir les changements au moment où l'application répond à notre prochaine requête HTTP.

4. Gestion des dépendances Ratpack-Groovy

Il existe plusieurs façons d'activer le support ratpack-groovy .

4.1. Grain de raisin

Nous pouvons utiliser le gestionnaire de dépendances intégré de Groovy, Grape.

C'est aussi simple que d'ajouter une annotation à notre script Ratpack.groovy :

@Grab('io.ratpack:ratpack-groovy:1.6.1') import static ratpack.groovy.Groovy.ratpack

4.2. Dépendance de Maven

Pour construire dans Maven, tout ce dont nous avons besoin est d'ajouter la dépendance pour la bibliothèque ratpack-groovy :

 io.ratpack ratpack-groovy ${ratpack.version}  

4.3. Gradle

Nous pouvons activer l' intégration ratpack-groovy , en ajoutant le plugin Gradle de Ratpack pour Groovy dans build.gradle :

plugins { id 'io.ratpack.ratpack-groovy' version '1.6.1' }

5. Ratpack Handlers à Groovy

Les gestionnaires fournissent un moyen de gérer les demandes et les réponses Web . Les objets de demande et de réponse sont accessibles dans cette fermeture.

Nous pouvons traiter les requêtes Web à l'aide de méthodes HTTP telles que GET et POST :

handlers { get("greet/:name") { ctx -> render "Hello " + ctx.getPathTokens().get("name") + " !!!" } } 

Nous pouvons tester cette requête Web via // localhost: 5050 / greet / :

$ curl -s localhost:5050/greet/Norman Hello Norman!!!

Dans le code du gestionnaire, ctx est l' objet de registre de contexte qui accorde l'accès aux variables de chemin, aux objets de requête et de réponse.

Les gestionnaires prennent également en charge la gestion de JSON via Jackson.

Retournons JSON, converti à partir d'une carte Groovy:

get("data") { render Jackson.json([title: "Mr", name: "Norman", country: "USA"]) } 
$ curl -s localhost:5050/data {"title":"Mr","name":"Norman","country":"USA"}

Ici, Jackson.json est utilisé pour effectuer la conversion.

6. Ratpack Promises à Groovy

Comme nous le savons, Ratpack active les fonctionnalités asynchrones et non bloquantes de l'application. Ceci est mis en œuvre avec Ratpack Promises.

Les promesses sont similaires à celles utilisées en JavaScript et sont un peu comme un futur Java . On peut penser à une promesse comme la représentation d'une valeur qui sera disponible dans le futur:

post("user") { Promise user = parse(Jackson.fromJson(User)) user.then { u -> render u.name } }

La dernière action ici est l' action then , qui détermine quoi faire avec la valeur finale. Dans ce cas, nous le renvoyons en réponse au POST.

Let's understand this code in more detail. Here, Jackson.fromJson parses the JSON of the request body using the ObjectMapperUser. Then, the inbuilt Context.parse method binds it to the Promise object.

The promise operates asynchronously. When the then operation is eventually performed, the response is returned:

curl -X POST -H 'Content-type: application/json' --data \ '{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \ //localhost:5050/employee Jiney Weiber

We should note that the Promise library is quite rich, allowing us to chain actions using functions like map and flatMap.

7. Integration with a Database

Having asynchronous handlers is of most benefit when our handlers have to wait for services. Let's demonstrate this by integrating our Ratpack application with an H2 database.

We can either use the Ratpack's HikariModule class which is an extension of HikariCP JDBC connection pool, or Groovy Sql for database integration.

7.1. HikariModule

To add HikariCP support, let's first add the following Hikari and H2 maven dependencies in our pom.xml:

 io.ratpack ratpack-hikari ${ratpack.version}   com.h2database h2 ${h2.version} 

Or, we can add the following dependencies to our build.gradle:

dependencies { compile ratpack.dependency('hikari') compile "com.h2database:h2:$h2.version" }

Now, we'll declare HikariModule under the bindings closure for the connection pool:

import ratpack.hikari.HikariModule ratpack { bindings { module(HikariModule) { config -> config.dataSourceClassName = 'org.h2.jdbcx.JdbcDataSource' config.addDataSourceProperty('URL', "jdbc:h2:mem:devDB;INIT=RUNSCRIPT FROM 'classpath:/User.sql'") } } } 

Finally, we're all set to use it for simple database operations using Java's Connection and PreparedStatement:

get('fetchUserName/:id') { Context ctx -> Connection connection = ctx.get(DataSource.class).getConnection() PreparedStatement queryStatement = connection.prepareStatement("SELECT NAME FROM USER WHERE ID=?") queryStatement.setInt(1, Integer.parseInt(ctx.getPathTokens().get("id"))) ResultSet resultSet = queryStatement.executeQuery() resultSet.next() render resultSet.getString(1) } 

Let's check that the handler works as expected:

$ curl -s localhost:5050/fetchUserName/1 Norman Potter

7.2. Groovy Sql Class

We can use Groovy Sql for quick database operations, through methods like rows and executeInsert:

get('fetchUsers') { def db = [url:'jdbc:h2:mem:devDB'] def sql = Sql.newInstance(db.url, db.user, db.password) def users = sql.rows("SELECT * FROM USER"); render(Jackson.json(users)) } 
$ curl -s localhost:5050/fetchUsers [{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"}, {"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]

Let's write an HTTP POST example with Sql:

post('addUser') { parse(Jackson.fromJson(User)) .then { u -> def db = [url:'jdbc:h2:mem:devDB'] Sql sql = Sql.newInstance(db.url, db.user, db.password) sql.executeInsert("INSERT INTO USER VALUES (?,?,?,?)", [u.id, u.title, u.name, u.country]) render "User $u.name inserted" } }
$ curl -X POST -H 'Content-type: application/json' --data \ '{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \ //localhost:5050/addUser User Jiney Weiber inserted

8. Unit Testing

8.1. Setting up the Tests

As discussed, Ratpack also provides the ratpack-groovy-test library for testing a ratpack-groovy application.

To use it, we can add it as Maven dependency in our pom.xml:

 io.ratpack ratpack-groovy-test 1.6.1 

Alternatively, we can add the Gradle dependency in our build.gradle:

testCompile ratpack.dependency('groovy-test')

Then we need to create a Groovy main class RatpackGroovyApp.groovy to let us test the Ratpack.groovy script.

public class RatpackGroovyApp { public static void main(String[] args) { File file = new File("src/main/groovy/com/baeldung/Ratpack.groovy"); def shell = new GroovyShell() shell.evaluate(file) } }

When running Groovy tests as JUnit tests, the class will invoke the Ratpack.groovy script using GroovyShell. In turn, it will start the Ratpack server for testing.

Now, let's write our Groovy Test class RatpackGroovySpec.groovy along with the code to start the Ratpack server through the RatpackGroovyApp:

class RatpackGroovySpec { ServerBackedApplicationUnderTest ratpackGroovyApp = new MainClassApplicationUnderTest(RatpackGroovyApp.class) @Delegate TestHttpClient client = TestHttpClient.testHttpClient(ratpackGroovyApp) }

Ratpack provides MainClassApplicationUnderTest to mock the application class for starting the server.

8.2. Writing Our Tests

Let's write our tests, starting with a very basic test to check if the application can start:

@Test void "test if app is started"() { when: get("") then: assert response.statusCode == 200 assert response.body.text == "Hello World from Ratpack with Groovy!!" }

Let's now write another test to verify the response of the fetchUsers get handler:

@Test void "test fetchUsers"() { when: get("fetchUsers") then: assert response.statusCode == 200 assert response.body.text == '[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]' }

The Ratpack test framework takes care of starting and stopping the server for us.

9. Conclusion

In this article, we’ve seen a few ways to write HTTP handlers for Ratpack using Groovy. We also explored Promises and Database integration.

We've seen how Groovy closures, DSLs, and Groovy's Sql make our code concise, efficient and readable. At the same time, Groovy's test support makes unit and integration testing straightforward.

With these techniques, we can use Groovy's dynamic language features, and expressive APIs, to rapidly develop high-performance, scalable HTTP applications with Ratpack.

Comme d'habitude, l'exemple de code peut être trouvé sur GitHub.