API mit dem Spark Java Framework erstellen

Erstellen einer API mit dem Spark Java Framework

1. Einführung

In diesem Artikel erhalten wir eine kurze Einführung inSpark framework. Das Spark-Framework ist ein Web-Framework für die schnelle Entwicklung, das vom Sinatra-Framework für Ruby inspiriert ist. Es basiert auf der Java 8 Lambda Expression-Philosophie und ist daher weniger ausführlich als die meisten Anwendungen, die in anderen Java-Frameworks geschrieben wurden.

Dies ist eine gute Wahl, wenn Sie bei der Entwicklung einer Web-API oder von Microservices in Java Erfahrung inNode.jshaben möchten. Mit Spark können Sie eine REST-API bereitstellen, um JSON in weniger als zehn Codezeilen bereitzustellen.

Wir werden einen kurzen Einstieg mit einem "Hello World" -Beispiel machen, gefolgt von einer einfachen REST-API.

2. Maven-Abhängigkeiten

2.1. Spark Framework

Nehmen Sie die folgende Maven-Abhängigkeit in Ihrepom.xmlauf:


    com.sparkjava
    spark-core
    2.5.4

Sie finden die neueste Version von Spark aufMaven Central.

2.2. Gson Bibliothek

An verschiedenen Stellen im Beispiel wird die Gson-Bibliothek für JSON-Operationen verwendet. Um Gson in Ihr Projekt aufzunehmen, fügen Sie diese Abhängigkeit in Ihrepom.xml ein:


    com.google.code.gson
    gson
    2.8.0

Sie finden die neueste Version von Gson aufMaven Central.

3. Erste Schritte mit Spark Framework

Werfen wir einen Blick auf die Grundbausteine ​​einer Spark-Anwendung und demonstrieren einen schnellen Webdienst.

3.1. Routen

Webdienste in Spark Java basieren auf Routen und ihren Handlern. Routen sind wesentliche Elemente in Spark. Gemäßdocumentation besteht jede Route aus drei einfachen Teilen - averb, apath und acallback.

  1. verb ist eine Methode, die einer HTTP-Methode entspricht. Verbmethoden umfassen:get, post, put, delete, head, trace, connect, undoptions

  2. Daspath (auch als Routenmuster bezeichnet) bestimmt, auf welche URI (s) die Route hören und eine Antwort geben soll

  3. callback ist eine Handlerfunktion, die für ein bestimmtes Verb und einen bestimmten Pfad aufgerufen wird, um eine Antwort auf die entsprechende HTTP-Anforderung zu generieren und zurückzugeben. Ein Rückruf nimmt ein Anforderungs- und ein Antwortobjekt als Argumente

Hier zeigen wir die Grundstruktur für eine Route, die das Verbgetverwendet:

get("/your-route-path/", (request, response) -> {
    // your callback code
});

3.2. Hallo Welt API

Erstellen wir einen einfachen Webdienst, der zwei Routen für GET-Anforderungen enthält und als Antwort "Hallo" -Nachrichten zurückgibt. Diese Routen verwenden die Methodeget, bei der es sich um einen statischen Import aus der Klassespark.Sparkhandelt:

import static spark.Spark.*;

public class HelloWorldService {
    public static void main(String[] args) {

        get("/hello", (req, res)->"Hello, world");

        get("/hello/:name", (req,res)->{
            return "Hello, "+ req.params(":name");
        });
    }
}

Das erste Argument für dieget-Methode ist der Pfad für die Route. Die erste Route enthält einen statischen Pfad, der nur einen einzelnen URI (“/hello”) darstellt.

Der Pfad der zweiten Route (“/hello/:name”) enthält einen Platzhalter für den Parameter“name”, der durch Voranstellen des Parameters mit einem Doppelpunkt (":") gekennzeichnet ist. Diese Route wird als Antwort auf GET-Anforderungen an URIs wie“/hello/Joe” und“/hello/Mary” aufgerufen.

Das zweite Argument für dieget-Methode istlambda expression, das diesem Framework eine funktionale Programmiervariante verleiht.

Der Lambda-Ausdruck hat Request und Response als Argumente und hilft, die Response zurückzugeben. Wir werden unsere Controller-Logik in den Lambda-Ausdruck für die REST-API-Routen einfügen, wie wir später in diesem Lernprogramm sehen werden.

3.3. Testen der Hello World API

Nachdem Sie die KlasseHelloWorldService als normale Java-Klasse ausgeführt haben, können Sie über die mit der obigen Methodeget definierten Routen über den Standardport4567 auf den Dienst zugreifen.

Schauen wir uns die Anfrage und Antwort für die erste Route an:

Anfrage:

GET http://localhost:4567/hello

Antwort:

Hello, world

Testen wir die zweite Route und übergeben Sie den Parameternamein seinem Pfad:

Anfrage:

GET http://localhost:4567/hello/example

Antwort:

Hello, example

Sehen Sie, wie die Platzierung des Textes“example” in der URI verwendet wurde, um mit dem Routenmuster“/hello/:name” übereinzustimmen. Dadurch wurde die Rückruffunktion der zweiten Route aufgerufen.

4. Entwerfen eines RESTful Service

In diesem Abschnitt entwerfen wir einen einfachen REST-Webdienst für die folgendeUser-Entität:

public class User {
    private String id;
    private String firstName;
    private String lastName;
    private String email;

    // constructors, getters and setters
}

4.1. Routen

Lassen Sie uns die Routen auflisten, aus denen unsere API besteht:

  • GET / users - Liste aller Benutzer abrufen

  • GET / users /: id - Liefert den Benutzer mit der angegebenen ID

  • POST / users /: id - Benutzer hinzufügen

  • PUT / users /: id - bearbeitet einen bestimmten Benutzer

  • OPTIONEN / Benutzer /: ID - Überprüfen Sie, ob ein Benutzer mit der angegebenen ID vorhanden ist

  • DELETE / users /: id - Löscht einen bestimmten Benutzer

4.2. Der Benutzerdienst

Unten ist dieUserService-Schnittstelle, die die CRUD-Operationen für dieUser-Entität deklariert:

public interface UserService {

    public void addUser (User user);

    public Collection getUsers ();
    public User getUser (String id);

    public User editUser (User user)
      throws UserException;

    public void deleteUser (String id);

    public boolean userExist (String id);
}

Zu Demonstrationszwecken stellen wir eineMap-Implementierung dieserUserService-Schnittstelle im GitHub-Code bereit, um die Persistenz zu simulieren. You can supply your own implementation with the database and persistence layer of your choice.

4.3. Die JSON-Antwortstruktur

Nachfolgend finden Sie die JSON-Struktur der Antworten, die in unserem REST-Service verwendet werden:

{
    status: 
    message: 
    data: 
}

Der Feldwertstatus kann entwederSUCCESS oderERROR sein. Das Felddata enthält die JSON-Darstellung der Rückgabedaten, z. B.User oder eine Sammlung vonUsers.

Wenn keine Daten zurückgegeben werden oder wennstatusERROR ist, füllen wir das Feldmessage aus, um einen Grund für den Fehler oder das Fehlen von Rückgabedaten anzugeben.

Stellen wir die obige JSON-Struktur mithilfe einer Java-Klasse dar:

public class StandardResponse {

    private StatusResponse status;
    private String message;
    private JsonElement data;

    public StandardResponse(StatusResponse status) {
        // ...
    }
    public StandardResponse(StatusResponse status, String message) {
        // ...
    }
    public StandardResponse(StatusResponse status, JsonElement data) {
        // ...
    }

    // getters and setters
}

wobeiStatusResponse einenum ist, das wie folgt definiert ist:

public enum StatusResponse {
    SUCCESS ("Success"),
    ERROR ("Error");

    private String status;
    // constructors, getters
}

5. RESTful Services implementieren

Implementieren wir nun die Routen und Handler für unsere REST-API.

5.1. Controller erstellen

Die folgende Java-Klasse enthält die Routen für unsere API, einschließlich der Verben und Pfade sowie eine Übersicht der Handler für jede Route:

public class SparkRestExample {
    public static void main(String[] args) {
        post("/users", (request, response) -> {
            //...
        });
        get("/users", (request, response) -> {
            //...
        });
        get("/users/:id", (request, response) -> {
            //...
        });
        put("/users/:id", (request, response) -> {
            //...
        });
        delete("/users/:id", (request, response) -> {
            //...
        });
        options("/users/:id", (request, response) -> {
            //...
        });
    }
}

In den folgenden Unterabschnitten wird die vollständige Implementierung der einzelnen Routenhandler gezeigt.

5.2. Benutzer hinzufügen

Unten sehen Sie den Methodenantwort-Handler vonpost, derUser hinzufügt:

post("/users", (request, response) -> {
    response.type("application/json");
    User user = new Gson().fromJson(request.body(), User.class);
    userService.addUser(user);

    return new Gson()
      .toJson(new StandardResponse(StatusResponse.SUCCESS));
});

Note: In diesem Beispiel wird die JSON-Darstellung desUser-Objekts als Rohkörper einer POST-Anforderung übergeben.

Testen wir die Route:

Anfrage:

POST http://localhost:4567/users
{
    "id": "1012",
    "email": "[email protected]",
    "firstName": "Mac",
    "lastName": "Mason1"
}

Antwort:

{
    "status":"SUCCESS"
}

5.3. Alle Benutzer abrufen

Unten finden Sie den Methodenantwort-Handlerget, der alle Benutzer vonUserService zurückgibt:

get("/users", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS,new Gson()
        .toJsonTree(userService.getUsers())));
});

Testen wir nun die Route:

Anfrage:

GET http://localhost:4567/users

Antwort:

{
    "status":"SUCCESS",
    "data":[
        {
            "id":"1014",
            "firstName":"John",
            "lastName":"Miller",
            "email":"[email protected]"
        },
        {
            "id":"1012",
            "firstName":"Mac",
            "lastName":"Mason1",
            "email":"[email protected]"
        }
    ]
}

5.4. Benutzer nach ID abrufen

Unten sehen Sie den Methodenantwort-Handlerget, derUser mit den angegebenenid zurückgibt:

get("/users/:id", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS,new Gson()
        .toJsonTree(userService.getUser(request.params(":id")))));
});

Testen wir nun die Route:

Anfrage:

GET http://localhost:4567/users/1012

Antwort:

{
    "status":"SUCCESS",
    "data":{
        "id":"1012",
        "firstName":"Mac",
        "lastName":"Mason1",
        "email":"[email protected]"
    }
}

5.5. Bearbeiten Sie einen Benutzer

Unten sehen Sie den Methodenantwort-Handlerput, der den Benutzer bearbeitet, der dieid im Routenmuster angegeben hat:

put("/users/:id", (request, response) -> {
    response.type("application/json");
    User toEdit = new Gson().fromJson(request.body(), User.class);
    User editedUser = userService.editUser(toEdit);

    if (editedUser != null) {
        return new Gson().toJson(
          new StandardResponse(StatusResponse.SUCCESS,new Gson()
            .toJsonTree(editedUser)));
    } else {
        return new Gson().toJson(
          new StandardResponse(StatusResponse.ERROR,new Gson()
            .toJson("User not found or error in edit")));
    }
});

Note: In diesem Beispiel werden die Daten im Rohtext einer POST-Anforderung als JSON-Objekt übergeben, dessen Eigenschaftsnamen mit den Feldern des zu bearbeitendenUser-Objekts übereinstimmen.

Testen wir die Route:

Anfrage:

PUT http://localhost:4567/users/1012
{
    "lastName": "Mason"
}

Antwort:

{
    "status":"SUCCESS",
    "data":{
        "id":"1012",
        "firstName":"Mac",
        "lastName":"Mason",
        "email":"[email protected]"
    }
}

5.6. Löschen Sie einen Benutzer

Unten ist der Methodenantwort-Handler vondelete, der dieUser mit den angegebenenid löscht:

delete("/users/:id", (request, response) -> {
    response.type("application/json");
    userService.deleteUser(request.params(":id"));
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS, "user deleted"));
});

Testen wir nun die Route:

Anfrage:

DELETE http://localhost:4567/users/1012

Antwort:

{
    "status":"SUCCESS",
    "message":"user deleted"
}

5.7. Überprüfen Sie, ob ein Benutzer vorhanden ist

Die Methodeoptions ist eine gute Wahl für die bedingte Überprüfung. Unten ist der Methodenantwort-Handler vonoptions, der prüft, ob einUser mit dem angegebenenid existiert:

options("/users/:id", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS,
        (userService.userExist(
          request.params(":id"))) ? "User exists" : "User does not exists" ));
});

Testen wir nun die Route:

Anfrage:

OPTIONS http://localhost:4567/users/1012

Antwort:

{
    "status":"SUCCESS",
    "message":"User exists"
}

6. Fazit

In diesem Artikel wurde eine kurze Einführung in das Spark-Framework für die schnelle Webentwicklung gegeben.

Dieses Framework wird hauptsächlich zur Generierung von Microservices in Java eingesetzt. Node.jsEntwickler mit Java-Kenntnissen, die auf JVM-Bibliotheken basierende Bibliotheken nutzen möchten, sollten sich mit diesem Framework wie zu Hause fühlen.

Und wie immer finden Sie alle Quellen für dieses Tutorial inGithub project.