Ratpack mit Groovy

1. Übersicht

Ratpack ist eine Reihe leichter Java-Bibliotheken zum Erstellen skalierbarer HTTP-Anwendungen mit reaktiven, asynchronen und nicht blockierenden Funktionen.

Darüber hinaus bietet Ratpack auch die Integration mit Technologien und Frameworks wie Google Guice, Spring Boot, RxJava und Hystrix.

In diesem Tutorial erfahren Sie, wie Sie Ratpack mit Groovy verwenden .

2. Warum Groovy?

Groovy ist eine leistungsstarke, dynamische Sprache, die in der JVM ausgeführt wird.

Daher macht Groovy Skripte und domänenspezifische Sprachen wirklich einfach. Mit Ratpack ermöglicht dies eine schnelle Entwicklung von Webanwendungen.

Ratpack bietet eine einfache Integration mit Groovy über die Testbibliotheken ratpack-groovy und ratpack -groovy .

3. Ratpack-Anwendung mit Groovy Script

Die Ratpack Groovy-APIs sind in Java integriert, sodass sie problemlos in Java- und Groovy-Anwendungen integriert werden können. Sie sind im Paket ratpack.groovy verfügbar .

In Kombination mit Groovys Skriptfähigkeiten und dem Traubenabhängigkeitsmanagement können wir schnell eine Ratpack-basierte Webanwendung in nur wenigen Zeilen erstellen:

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

Dies ist unser erster Handler, der eine GET-Anfrage bearbeitet. Alles, was wir tun mussten, war, ein grundlegendes DSL hinzuzufügen, um den Ratpack-Server zu aktivieren.

Lassen Sie uns dies jetzt als Groovy-Skript ausführen, um die Anwendung zu starten. Standardmäßig ist die Anwendung unter // localhost: 5050 : verfügbar.

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

Wir können den Port auch mit ServerConfig konfigurieren :

ratpack { serverConfig { port(5056) } }

Ratpack bietet auch eine Hot-Reloading-Funktion , mit der wir Ratpack.groovy ändern und die Änderungen dann sehen können, sobald die Anwendung unsere nächste HTTP-Anfrage bearbeitet .

4. Ratpack-Groovy-Abhängigkeitsmanagement

Es gibt verschiedene Möglichkeiten, um Ratpack-Groovy- Unterstützung zu ermöglichen .

4.1. Traube

Wir können Groovys eingebetteten Abhängigkeitsmanager Grape verwenden.

Es ist so einfach wie das Hinzufügen einer Anmerkung zu unserem Ratpack.groovy- Skript:

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

4.2. Maven-Abhängigkeit

Für das Bauen in Maven müssen wir lediglich die Abhängigkeit für die ratpack-groovige Bibliothek hinzufügen :

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

4.3. Gradle

Wir können die Ratpack-Groovy- Integration aktivieren , indem wir das Ratpack-Gradle-Plugin für Groovy in build.gradle hinzufügen :

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

5. Ratpack-Handler in Groovy

Handler bieten eine Möglichkeit, Webanforderungen und -antworten zu verarbeiten . Auf die Anforderungs- und Antwortobjekte kann in diesem Abschluss zugegriffen werden.

Wir können Webanfragen mit HTTP-Methoden wie GET und POST bearbeiten :

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

Wir können diese Webanforderung über // localhost: 5050 / greet / : testen.

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

Im Code des Handlers ist ctx das Kontextregistrierungsobjekt, das Zugriff auf Pfadvariablen, Anforderungs- und Antwortobjekte gewährt.

Handler haben auch Unterstützung für den Umgang mit JSON über Jackson.

Lassen Sie uns JSON zurückgeben, das von einer Groovy-Map konvertiert wurde:

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

Hier wird Jackson.json verwendet, um die Konvertierung durchzuführen .

6. Ratpack verspricht in Groovy

Wie wir wissen, aktiviert Ratpack die asynchronen und nicht blockierenden Funktionen in der Anwendung. Dies wird mit Ratpack Promises implementiert.

Versprechen ähneln denen, die in JavaScript verwendet werden, und ähneln ein bisschen einer Java- Zukunft . Wir können uns ein Versprechen als Repräsentation eines Wertes vorstellen, der in Zukunft verfügbar sein wird:

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

Die letzte Aktion hier ist die Aktion then , die bestimmt, was mit dem Endwert zu tun ist. In diesem Fall senden wir es als Antwort auf den POST zurück.

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.

Der Beispielcode befindet sich wie gewohnt auf GitHub.