Einführung in RESTX

Einführung in RESTX

1. Überblick

In diesem Tutorial werden wir einen Rundgang durch das leichtgewichtige Java REST-FrameworkRESTX machen.

2. Eigenschaften

Das Erstellen einer RESTful-API ist mit dem RESTX-Framework ganz einfach. Es verfügt über alle Standardeinstellungen, die wir von einem REST-Framework erwarten können, z. B. das Bereitstellen und Verwenden von JSON, Abfrage- und Pfadparameter, Routing- und Filtermechanismen, Nutzungsstatistiken und Überwachung.

RESTX enthält außerdem eine intuitive Admin-Webkonsole und ein Befehlszeilen-Installationsprogramm für einfaches Bootstrapping.

Es ist auch unter der Apache-Lizenz 2 lizenziert und wird von einer Community von Entwicklern verwaltet. Die minimale Java-Anforderung für RESTX ist JDK 7.

3. Aufbau

RESTX wird mit einer praktischen Shell- / Befehls-App geliefert, mit der Sie ein Java-Projekt schnell booten können.

Wir müssen die App zuerst installieren, bevor wir fortfahren können. Die detaillierte Installationsanleitung ist inhere verfügbar.

4. Core Plugins installieren

Jetzt ist es an der Zeit, die Kern-Plugins zu installieren, um eine App aus der Shell selbst erstellen zu können.

Führen Sie in der RESTX-Shell den folgenden Befehl aus:

shell install

Sie werden dann aufgefordert, die Plugins für die Installation auszuwählen. Wir müssen die Zahl auswählen, die aufio.restx:restx-core-shell zeigt. The shell will automatically restart once installation completes.

5. Shell App Bootstrap

Mit der RESTX-Shell ist es sehr bequem, eine neue App zu booten. Es enthält eine assistentenbasierte Anleitung.

Zunächst führen wir den folgenden Befehl in der Shell aus:

app new

Dieser Befehl löst den Assistenten aus. Dann können wir entweder die Standardoptionen verwenden oder sie gemäß unseren Anforderungen ändern:

imageimage

Da wir uns entschieden haben,pom.xml, zu generieren, kann das Projekt problemlos in jede Standard-Java-IDE importiert werden.

In einigen Fällen müssen wir möglicherweisethe IDE settings anpassen.

Unser nächster Schritt wird sein, das Projekt zu bauen:

mvn clean install -DskipTests

Once the build is successful we can run the AppServer class as a Java Application from the IDE. Dadurch wird der Server mit der Administratorkonsole gestartet, die Port 8080 überwacht.

Wir können zuhttp://127.0.0.1:8080/api/@/ui and navigieren, um die grundlegende Benutzeroberfläche zu sehen.

Die Routen, die mit/@/ beginnen, werden für die Administratorkonsole verwendet, die in RESTX ein reservierter Pfad ist.

Um sich bei der Administratorkonsole anzumelden, können wir den Standardbenutzernamen „admin und das Kennwort verwenden, das wir beim Erstellen der App angegeben haben.

Bevor wir mit der Konsole herumspielen, wollen wir den Code untersuchen und verstehen, was der Assistent generiert hat.

6. Eine RESTX-Ressource

Die Routen sind in der Klasse <main_package>.rest.HelloResourcedefiniert:

@Component
@RestxResource
public class HelloResource {
    @GET("/message")
    @RolesAllowed(Roles.HELLO_ROLE)
    public Message sayHello() {
        return new Message().setMessage(String.format("hello %s, it's %s",
          RestxSession.current().getPrincipal().get().getName(),
          DateTime.now().toString("HH:mm:ss")));
    }
}

Es ist sofort ersichtlich, dass RESTX Standard-J2EE-Annotationen für Sicherheits- und REST-Bindungen verwendet. Zum größten Teil werden eigene Annotationen für die Abhängigkeitsinjektion verwendet.

RESTX unterstützt auch viele vernünftige Standardeinstellungen fürmapping method parameters to the request.

Zusätzlich zu diesen Standardanmerkungen ist@RestxResource, was es als eine Ressource deklariert, die RESTX erkennt.

Der Basispfad wird insrc/main/webapp/WEB-INF/web.xml. hinzugefügt. In unserem Fall ist es/api, sodass wir eine GET-Anforderung anhttp://localhost:8080/api/message senden können, sofern eine ordnungsgemäße Authentifizierung vorausgesetzt wird.

Die KlasseMessageist nur eine Java-Bean, die RESTX für JSON serialisiert.

Wir steuern den Benutzerzugriff, indem wir die AnnotationRolesAllowed mitHELLO_ROLE angeben, die vom Bootstrapper generiert wurde.

7. Die Modulklasse

Wie bereits erwähnt, verwendet RESTX Annotationen zur Abhängigkeitsinjektion nach J2EE-Standard wie@Named und erfindet bei Bedarf eigene Annotationen, wobei wahrscheinlich ein Hinweis aus dem Dolch-Framework für@Module und@Provides. verwendet wird

Damit werden die Hauptmodule der Anwendung erstellt, die unter anderem das Administratorkennwort definieren:

@Module
public class AppModule {

    @Provides
    public SignatureKey signatureKey() {
        return new SignatureKey("restx-demo -44749418370 restx-demo 801f-4116-48f2-906b"
            .getBytes(Charsets.UTF_8));
    }

    @Provides
    @Named("restx.admin.password")
    public String restxAdminPassword() {
        return "1234";
    }

    @Provides
    public ConfigSupplier appConfigSupplier(ConfigLoader configLoader) {
        return configLoader.fromResource("restx/demo/settings");
    }

    // other provider methods to create components
}

@Module definiert eine Klasse, die andere Komponenten definieren kann, ähnlich wie@Module in Dagger oder@Configuration in Spring.

@Provides macht eine Komponente programmgesteuert verfügbar, z. B.@Provides in Dagger oder@Bean im Frühjahr.

Und schließlich wird die Annotation@Namedverwendet, um den Namen der erzeugten Komponente anzugeben.

AppModule bietet auchSignatureKey zum Signieren von an die Clients gesendeten Inhalten. Beim Erstellen der Sitzung für die Beispiel-App wird beispielsweise ein Cookie gesetzt, das mit dem konfigurierten Schlüssel signiert ist:

HTTP/1.1 200 OK
...
Set-Cookie: RestxSessionSignature-restx-demo="ySfv8FejvizMMvruGlK3K2hwdb8="; RestxSession-restx-demo="..."
...

8. Die Launcher-Klasse

Und schließlich wird die KlasseAppSerververwendet, um die Anwendung als Standard-Java-App auf einem eingebetteten Jetty-Server auszuführen:

public class AppServer {
    public static final String WEB_INF_LOCATION = "src/main/webapp/WEB-INF/web.xml";
    public static final String WEB_APP_LOCATION = "src/main/webapp";

    public static void main(String[] args) throws Exception {
        int port = Integer.valueOf(Optional.fromNullable(System.getenv("PORT")).or("8080"));
        WebServer server =
            new Jetty8WebServer(WEB_INF_LOCATION, WEB_APP_LOCATION, port, "0.0.0.0");
        System.setProperty("restx.mode", System.getProperty("restx.mode", "dev"));
        System.setProperty("restx.app.package", "restx.demo");
        server.startAndAwait();
    }
}

Hier wird derdev-Modus während der Entwicklungsphase verwendet, um Funktionen wie die automatische Kompilierung zu aktivieren, die die Entwicklungsrückkopplungsschleife verkürzt.

Wir können die App alswar-Datei (Webarchiv) verpacken, um sie in einem eigenständigen J2EE-Webcontainer bereitzustellen.

Im nächsten Abschnitt erfahren Sie, wie Sie die App testen.

9. Integrationstests mit Specs

Eine der Stärken von RESTX ist das Konzept der „Spezifikationen“. Eine Stichprobespec würde folgendermaßen aussehen:

title: should admin say hello
given:
  - time: 2013-08-28T01:18:00.822+02:00
wts:
  - when: |
      GET hello?who=xavier
    then: |
      {"message":"hello xavier, it's 01:18:00"}

Der Test wird in einerGiven-When-Then-Struktur in einerYAML-Datei geschrieben, die im Wesentlichen definiert, wie die API bei einem aktuellen Status auf eine bestimmte Anforderung (when) reagieren soll (then) des Systems (given).

Die KlasseHelloResourceSpecTest insrc/test/resources löst die in den obigen Spezifikationen beschriebenen Tests aus:

@RunWith(RestxSpecTestsRunner.class)
@FindSpecsIn("specs/hello")
public class HelloResourceSpecTest {}

Die KlasseRestxSpecTestsRunner istcustom JUnit runner. Es enthält benutzerdefinierte JUnit-Regeln für Folgendes:

  • Richten Sie einen eingebetteten Server ein

  • Bereiten Sie den Status des Systems vor (gemäß dem Abschnittgiven in den Spezifikationen).

  • die angegebenen Anforderungen ausgeben und

  • Überprüfen Sie die erwarteten Antworten

Die Annotation@FindSpecsIn zeigt auf den Pfad der Spezifikationsdateien, für die die Tests ausgeführt werden sollen.

The spec helps to write integration tests and provide examples in the API docs. Spezifikationen sind auch fürmock HTTP requests and record request/response pairs nützlich.

10. Manuelle Prüfung

Wir können auch manuell über HTTP testen. Wir müssen uns zuerst anmelden und dazu müssen wir das Administratorkennwort in der RESTX-Konsole hashen:

hash md5 

Und dann können wir das an den Endpunkt von/sessionsübergeben:

curl -b u1 -c u1 -X POST -H "Content-Type: application/json"
  -d '{"principal":{"name":"admin","passwordHash":"1d528266b85cf052803a57288"}}'
  http://localhost:8080/api/sessions

(Beachten Sie, dass Windows-Benutzer zuerstdownload locken müssen.)

Und jetzt, wenn wir die Sitzung als Teil unserer/message-Anforderung verwenden:

curl -b u1 "http://localhost:8080/api/message?who=restx"

Dann bekommen wir so etwas:

{"message" : "hello admin, it's 09:56:51"}

11. Entdecken Sie die Admin-Konsole

Die Administratorkonsole bietet nützliche Ressourcen zur Steuerung der App.

Schauen wir uns die wichtigsten Funktionen an, indem wir zuhttp://127.0.0.1:8080/admin/@/ui navigieren.

11.1. API-Dokumente

Im Abschnitt API-Dokumente werden alle verfügbaren Routen einschließlich aller Optionen aufgelistet:

imageimage

Und wir können auf einzelne Routen klicken und sie auf der Konsole selbst ausprobieren:

imageimage

11.2. Überwachung

Der AbschnittJVM Metrics zeigt die Anwendungsmetriken mit aktiven Sitzungen, Speichernutzung und Thread-Dump:

imageimage

UnterApplication Metrics werden hauptsächlich zwei Kategorien von Elementen standardmäßig überwacht:

  • BUILD entspricht der Instanziierung der Anwendungskomponenten

  • HTTP entspricht HTTP-Anforderungen, die von RESTX verarbeitet werden

11.3. Statistiken

Mit RESTX kann der Benutzer anonyme Statistiken für die Anwendung sammeln und freigeben, um Informationen an die RESTX-Community weiterzugeben. We can easily opt out by excluding the restx-stats-admin module.

Die Statistiken melden Dinge wie das zugrunde liegende Betriebssystem und die JVM-Version:

imageimage

Because this page shows sensitive information,make sure to review its configuration options.

Abgesehen davon kann uns die Admin-Konsole auch helfen:

  • Überprüfen Sie die Server-Protokolle (Protokolle)

  • Die aufgetretenen Fehler anzeigen (Fehler)

  • Überprüfen Sie die Umgebungsvariablen (Config)

12. Genehmigung

RESTX endpoints are secured by default. Das heißt, wenn für einen Endpunkt:

@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

Bei einem Aufruf ohne Authentifizierung wird standardmäßig401 by zurückgegeben.

Um einen Endpunkt öffentlich zu machen, müssen wir die Annotation@PermitAllentweder auf Methoden- oder Klassenebene verwenden:

@PermitAll
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

Beachten Sie, dass auf Klassenebene alle Methoden öffentlich sind.

Darüber hinaus ermöglicht das Framework auch die Angabe von Benutzerrollen mithilfe der Annotation@RolesAllowed:

@RolesAllowed("admin")
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

Mit dieser Anmerkung überprüft RESTX, ob dem authentifizierten Benutzer auch eine Administratorrolle zugewiesen wurde. Wenn ein authentifizierter Benutzer ohne Administratorrollen versucht, auf den Endpunkt zuzugreifen, gibt die Anwendung403 anstelle von401 zurück.

Standardmäßig werden die Benutzerrollen und Anmeldeinformationen im Dateisystem in separaten Dateien gespeichert.

Die Benutzer-ID mit dem verschlüsselten Passwort wird also unter der Datei/data/credentials.jsongespeichert:

{
    "user1": "$2a$10$iZluUbCseDOvKnoe",
    "user2": "$2a$10$oym3Swr7pScdiCXu"
}

Die Benutzerrollen sind in der Datei/data/users.jsondefiniert:

[
    {"name":"user1", "roles": ["hello"]},
    {"name":"user2", "roles": []}
]

In der Beispiel-App werden die Dateien über die KlasseFileBasedUserRepository inAppModule geladen:

new FileBasedUserRepository<>(StdUser.class, mapper,
  new StdUser("admin", ImmutableSet. of("*")),
  Paths.get("data/users.json"), Paths.get("data/credentials.json"), true)

Die KlasseStdUserenthält die Benutzerobjekte. Es kann eine benutzerdefinierte Benutzerklasse sein, sie muss jedoch in JSON serialisierbar sein.

Wir können natürlich eine andereUserRepository-Implementierung verwenden, wie eine, die auf eine Datenbank trifft.


13. Fazit

Dieses Tutorial gab einen Überblick über das schlanke Java-basierte RESTX-Framework.

Das Framework befindet sich noch in der Entwicklung und wird möglicherweise von rauen Kanten verwendet. Weitere Informationen finden Sie unterthe official documentation.

Die Beispiel-Bootstrap-App ist in unserenGitHub repository verfügbar.