Erstellen von REST-Microservices mit Javalin

1. Einleitung

Javalin ist ein leichtes Webframework, das für Java und Kotlin geschrieben wurde. Es ist auf dem Jetty-Webserver geschrieben, was es sehr leistungsfähig macht. Javalin ist eng an koa.js angelehnt, was bedeutet, dass es von Grund auf geschrieben wurde, um einfach zu verstehen und darauf aufzubauen.

In diesem Tutorial werden wir die Schritte zum Erstellen eines grundlegenden REST-Mikroservices mit diesem Light-Framework durchgehen.

2. Abhängigkeiten hinzufügen

Um eine Basisanwendung zu erstellen, benötigen wir nur eine Abhängigkeit - Javalin selbst:

 io.javalin javalin 1.6.1 

Die aktuelle Version finden Sie hier.

3. Javalin einrichten

Javalin erleichtert das Einrichten einer Basisanwendung. Zunächst definieren wir unsere Hauptklasse und richten eine einfache „Hello World“ -Anwendung ein.

Erstellen wir eine neue Datei in unserem Basispaket mit dem Namen JavalinApp.java .

In dieser Datei erstellen wir eine Hauptmethode und fügen Folgendes hinzu, um eine Basisanwendung einzurichten:

Javalin app = Javalin.create() .port(7000) .start(); app.get("/hello", ctx -> ctx.html("Hello, Javalin!"));

Wir erstellen eine neue Instanz von Javalin, lassen sie auf Port 7000 abhören und starten dann die Anwendung.

Wir richten auch unseren ersten Endpunkt ein, der auf eine GET- Anfrage am / hello- Endpunkt wartet .

Lassen Sie uns diese Anwendung ausführen und // localhost: 7000 / hello besuchen, um die Ergebnisse zu sehen.

4. Erstellen eines UserControllers

Ein Beispiel für „Hallo Welt“ eignet sich hervorragend für die Einführung eines Themas, ist jedoch für eine echte Anwendung nicht vorteilhaft. Schauen wir uns jetzt einen realistischeren Anwendungsfall für Javalin an.

Zuerst müssen wir ein Modell des Objekts erstellen, mit dem wir arbeiten. Wir beginnen mit der Erstellung eines Pakets namens user unter dem Root-Projekt.

Dann fügen wir eine neue Benutzerklasse hinzu :

public class User { public final int id; public final String name; // constructors }

Außerdem müssen wir unser Datenzugriffsobjekt (DAO) einrichten. In diesem Beispiel verwenden wir ein In-Memory-Objekt, um unsere Benutzer zu speichern.

Wir schaffen eine neue Klasse in dem Benutzer namens verpackt UserDao.java:

class UserDao { private List users = Arrays.asList( new User(0, "Steve Rogers"), new User(1, "Tony Stark"), new User(2, "Carol Danvers") ); private static UserDao userDao = null; private UserDao() { } static UserDao instance() { if (userDao == null) { userDao = new UserDao(); } return userDao; } Optional getUserById(int id) { return users.stream() .filter(u -> u.id == id) .findAny(); } Iterable getAllUsernames() { return users.stream() .map(user -> user.name) .collect(Collectors.toList()); } }

Die Implementierung unseres DAO als Singleton erleichtert die Verwendung im Beispiel. Wir könnten es auch als statisches Mitglied unserer Hauptklasse deklarieren oder die Abhängigkeitsinjektion aus einer Bibliothek wie Guice verwenden, wenn wir möchten.

Schließlich möchten wir unsere Controller-Klasse erstellen. Mit Javalin können wir sehr flexibel sein, wenn wir unsere Routenführer deklarieren. Dies ist also nur eine Möglichkeit, sie zu definieren.

Wir erstellen eine neue Klasse namens UserController.java im Benutzerpaket :

public class UserController { public static Handler fetchAllUsernames = ctx -> { UserDao dao = UserDao.instance(); Iterable allUsers = dao.getAllUsernames(); ctx.json(allUsers); }; public static Handler fetchById = ctx -> { int id = Integer.parseInt(Objects.requireNonNull(ctx.param("id"))); UserDao dao = UserDao.instance(); User user = dao.getUserById(id); if (user == null) { ctx.html("Not Found"); } else { ctx.json(user); } }; }

Indem wir die Handler als statisch deklarieren, stellen wir sicher, dass der Controller selbst keinen Status hat. In komplexeren Anwendungen möchten wir möglicherweise den Status zwischen Anforderungen speichern. In diesem Fall müssten wir den statischen Modifikator entfernen.

Beachten Sie auch, dass Unit-Tests mit statischen Methoden schwieriger sind. Wenn wir also diese Teststufe wünschen, müssen wir nicht statische Methoden verwenden.

5. Routen hinzufügen

Wir haben jetzt mehrere Möglichkeiten, Daten aus unserem Modell abzurufen. Der letzte Schritt besteht darin, diese Daten über REST-Endpunkte verfügbar zu machen. Wir müssen zwei neue Routen in unserer Hauptanwendung registrieren.

Fügen wir sie unserer Hauptanwendungsklasse hinzu:

app.get("/users", UserController.fetchAllUsernames); app.get("/users/:id", UserController.fetchById);

Nach dem Kompilieren und Ausführen der Anwendung können wir an jeden dieser neuen Endpunkte eine Anfrage stellen. Wenn Sie // localhost: 7000 / users aufrufen, werden alle Benutzer aufgelistet, und wenn Sie // localhost: 7000 / users / 0 aufrufen, erhalten Sie das JSON-Objekt für einen einzelnen Benutzer mit der ID 0. Wir haben jetzt einen Microservice, mit dem wir Benutzerdaten abrufen können.

6. Routen erweitern

Das Abrufen von Daten ist eine wichtige Aufgabe der meisten Microservices.

Wir müssen jedoch auch in der Lage sein, Daten in unserem Datenspeicher zu speichern. Javalin bietet den vollständigen Satz von Pfadhandlern, die zum Erstellen von Diensten erforderlich sind.

Wir haben oben ein Beispiel für GET gesehen , aber PATCH, POST, DELETE und PUT sind ebenfalls möglich.

Wenn wir Jackson als Abhängigkeit einbeziehen, können wir JSON-Anforderungskörper automatisch in unsere Modellklassen analysieren. Zum Beispiel:

app.post("/") { ctx -> User user = ctx.bodyAsClass(User.class); }

würde es uns ermöglichen, das JSON- Benutzerobjekt aus dem Anforderungshauptteil zu holen und es in das Benutzermodellobjekt zu übersetzen .

7. Fazit

Wir können all diese Techniken kombinieren, um unseren Microservice zu erstellen.

In diesem Artikel haben wir gesehen, wie Sie Javalin einrichten und eine einfache Anwendung erstellen. Wir haben auch darüber gesprochen, wie die verschiedenen HTTP-Methodentypen verwendet werden können, damit Clients mit unserem Service interagieren können.

Weitere Beispiele zur Verwendung von Javalin finden Sie in der Dokumentation.

Wie immer ist der Code auch auf GitHub zu finden.