1. 序章

この記事では、Sparkフレームワークについて簡単に紹介します。 Sparkフレームワークは、Ruby用のSinatraフレームワークに触発された急速な開発Webフレームワークであり、Java 8 Lambda Expression哲学に基づいて構築されているため、他のJavaフレームワークで記述されたほとんどのアプリケーションよりも冗長ではありません。

JavaでWebAPIまたはマイクロサービスを開発するときにNode.jsのようなエクスペリエンスが必要な場合に適しています。 Sparkを使用すると、10行未満のコードでJSONを提供するためのRESTAPIを準備できます。

「HelloWorld」の例から始めて、簡単なRESTAPIを続けます。

2. Mavenの依存関係

2.1. Sparkフレームワーク

pom.xmlに次のMaven依存関係を含めます。

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.5.4</version>
</dependency>

Sparkの最新バージョンはMavenCentralにあります。

2.2. Gsonライブラリ

例のさまざまな場所で、JSON操作にGsonライブラリを使用します。 プロジェクトにGsonを含めるには、この依存関係をpom.xmlに含めます。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.0</version>
</dependency>

Gsonの最新バージョンは、 MavenCentralにあります。

3. SparkFramework入門

Sparkアプリケーションの基本的な構成要素を見て、簡単なWebサービスを示しましょう。

3.1. ルート

Spark JavaのWebサービスは、ルートとそのハンドラーに基づいて構築されています。 ルートはSparkの重要な要素です。 ドキュメントによると、各ルートは、動詞パス、およびコールバックの3つの単純な部分で構成されています。

  1. 動詞は、HTTPメソッドに対応するメソッドです。 動詞の方法には、 get、post、put、delete、head、trace、connect、およびオプションが含まれます。
  2. パス(ルートパターンとも呼ばれます)は、ルートがリッスンするURIを決定し、
  3. コールバックは、対応するHTTPリクエストへの応答を生成して返すために、特定の動詞とパスに対して呼び出されるハンドラー関数です。 コールバックは、リクエストオブジェクトとレスポンスオブジェクトを引数として受け取ります

ここでは、get動詞を使用するルートの基本構造を示します。

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

3.2. Hello World API

GET要求に対して2つのルートがあり、応答として「Hello」メッセージを返す単純なWebサービスを作成してみましょう。 これらのルートは、 get メソッドを使用します。これは、クラスspark.Sparkからの静的インポートです。

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");
        });
    }
}

get メソッドの最初の引数は、ルートのパスです。 最初のルートには、単一のURI(“ / hello” )のみを表す静的パスが含まれています。

2番目のルートのパス(“ / hello /:name” )には、“ name” パラメーターのプレースホルダーが含まれています。これは、パラメーターの前にコロン(“:”)を付けることで示されます。 このルートは、“ / hello / Joe”“ / hello / Mary”などのURIへのGETリクエストに応答して呼び出されます。

get メソッドの2番目の引数は、ラムダ式であり、このフレームワークに関数型プログラミングのフレーバーを与えます。

ラムダ式には引数としてリクエストとレスポンスがあり、レスポンスを返すのに役立ちます。 このチュートリアルの後半で説明するように、コントローラーロジックをRESTAPIルートのラムダ式に配置します。

3.3. HelloWorldAPIのテスト

クラスHelloWorldServiceを通常のJavaクラスとして実行すると、 get で定義されたルートを使用して、デフォルトのポート4567でサービスにアクセスできるようになります。上記の方法。

最初のルートのリクエストとレスポンスを見てみましょう。

リクエスト:

GET http://localhost:4567/hello

応答:

Hello, world

パスにnameパラメーターを渡して、2番目のルートをテストしてみましょう。

リクエスト:

GET http://localhost:4567/hello/baeldung

応答:

Hello, baeldung

URI内のテキスト「baeldung」の配置がルートパターン「/hello/:name」と一致するためにどのように使用されたかを確認してください–2番目のルートのコールバックハンドラー関数が呼び出されます。

4. RESTfulサービスの設計

このセクションでは、次のUserエンティティ用の単純なRESTWebサービスを設計します。

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

    // constructors, getters and setters
}

4.1. ルート

APIを構成するルートをリストしてみましょう。

  • GET / users —すべてのユーザーのリストを取得します
  • GET / users /:id —指定されたIDのユーザーを取得します
  • POST / users /:id —ユーザーを追加します
  • PUT / users /:id —特定のユーザーを編集します
  • オプション/users/:id —指定されたIDのユーザーが存在するかどうかを確認します
  • DELETE / users /:id —特定のユーザーを削除します

4.2. ユーザーサービス

以下は、UserエンティティのCRUD操作を宣言するUserServiceインターフェイスです。

public interface UserService {
 
    public void addUser (User user);
    
    public Collection<User> getUsers ();
    public User getUser (String id);
    
    public User editUser (User user) 
      throws UserException;
    
    public void deleteUser (String id);
    
    public boolean userExist (String id);
}

デモンストレーションの目的で、永続性をシミュレートするために、このUserServiceインターフェイスのMap実装をGitHubコードで提供します。 選択したデータベースと永続性レイヤーを使用して独自の実装を提供できます。

4.3. JSON応答構造

以下は、RESTサービスで使用される応答のJSON構造です。

{
    status: <STATUS>
    message: <TEXT-MESSAGE>
    data: <JSON-OBJECT>
}

status フィールドの値は、SUCCESSまたはERRORのいずれかになります。 data フィールドには、UserUsersのコレクションなどの戻りデータのJSON表現が含まれます。

データが返されない場合、またはstatusERRORの場合、 message フィールドにデータを入力して、エラーまたは戻りの欠如の理由を伝えます。データ。

Javaクラスを使用して上記のJSON構造を表現しましょう。

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
}

ここで、 StatusResponse は、次のように定義されたenumです。

public enum StatusResponse {
    SUCCESS ("Success"),
    ERROR ("Error");
 
    private String status;       
    // constructors, getters
}

5. RESTfulサービスの実装

それでは、RESTAPIのルートとハンドラーを実装しましょう。

5.1. コントローラの作成

次のJavaクラスには、動詞とパス、および各ルートのハンドラーの概要を含む、APIのルートが含まれています。

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) -> {
            //...
        });
    }
}

次のサブセクションでは、各ルートハンドラーの完全な実装を示します。

5.2. ユーザーを追加する

以下は、Userを追加するpostメソッド応答ハンドラーです。

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));
});

注:この例では、 User オブジェクトのJSON表現が、POSTリクエストの生の本体として渡されます。

ルートをテストしてみましょう:

リクエスト:

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

応答:

{
    "status":"SUCCESS"
}

5.3. すべてのユーザーを取得

以下は、UserServiceからすべてのユーザーを返すgetメソッド応答ハンドラーです。

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

次に、ルートをテストしましょう。

リクエスト:

GET http://localhost:4567/users

応答:

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

5.4. IDでユーザーを取得

以下は、指定されたidUserを返すgetメソッド応答ハンドラーです。

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")))));
});

次に、ルートをテストしましょう。

リクエスト:

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

応答:

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

5.5. ユーザーを編集する

以下は、 put メソッド応答ハンドラーです。これは、ルートパターンでidが指定されているユーザーを編集します。

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")));
    }
});

注:この例では、データは、プロパティ名が編集対象のUserオブジェクトのフィールドと一致するJSONオブジェクトとしてPOSTリクエストの生の本文で渡されます。

ルートをテストしてみましょう:

リクエスト:

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

応答:

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

5.6. ユーザーを削除する

以下は、 delete メソッド応答ハンドラーです。これにより、指定されたidを持つUserが削除されます。

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

それでは、ルートをテストしてみましょう。

リクエスト:

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

応答:

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

5.7. ユーザーが存在するかどうかを確認します

options メソッドは、条件付きチェックに適しています。 以下は、指定されたidを持つUserが存在するかどうかをチェックするオプションメソッド応答ハンドラーです。

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" ));
});

次に、ルートをテストしましょう。

リクエスト:

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

応答:

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

6. 結論

この記事では、迅速なWeb開発のためのSparkフレームワークについて簡単に紹介しました。

このフレームワークは、主にJavaでマイクロサービスを生成するために推進されています。 Node.js Javaの知識があり、JVMライブラリ上に構築されたライブラリを活用したい開発者は、このフレームワークを使用することに慣れている必要があります。

そしていつものように、このチュートリアルのすべてのソースはGithubプロジェクトにあります。