1. 概要

このチュートリアルでは、軽量のJavaRESTフレームワークRESTXのツアーを行います。

2. 特徴

RESTful APIの構築は、RESTXフレームワークを使用すると非常に簡単です。 これには、JSONの提供と使用、クエリとパスのパラメーター、ルーティングとフィルタリングのメカニズム、使用統計、監視など、RESTフレームワークに期待できるすべてのデフォルトがあります。

RESTXには、ブートストラップを簡単にするための直感的な管理Webコンソールとコマンドラインインストーラーも付属しています。

また、Apache License 2の下でライセンスされ、開発者のコミュニティによって維持されています。 RESTXの最小Java要件はJDK7です。

3. 構成

RESTXには、Javaプロジェクトをすばやくブートストラップするのに役立つ便利なシェル/コマンドアプリが付属しています。

先に進む前に、まずアプリをインストールする必要があります。 詳細なインストール手順は、こちらにあります。

4. コアプラグインのインストール

次に、コアプラグインをインストールして、シェル自体からアプリを作成できるようにします。

RESTXシェルで、次のコマンドを実行してみましょう。

shell install

次に、インストールするプラグインを選択するように求められます。 io.restx:restx-core-shellを指す番号を選択する必要があります。 インストールが完了すると、シェルは自動的に再起動します。

5. シェルアプリのブートストラップ

RESTXシェルを使用すると、新しいアプリをブートストラップするのに非常に便利です。 ウィザードベースのガイドを提供します。

まず、シェルで次のコマンドを実行します。

app new

このコマンドはウィザードをトリガーします。 次に、デフォルトのオプションを使用するか、要件に従って変更することができます。

pom.xmlを生成することを選択したため、プロジェクトは任意の標準JavaIDEに簡単にインポートできます。

場合によっては、IDE設定を微調整する必要があります。

次のステップは、プロジェクトをビルドすることです。

mvn clean install -DskipTests

ビルドが成功したら、IDEからJavaアプリケーションとしてAppServerクラスを実行できます。 これにより、管理コンソールでサーバーが起動し、ポート8080でリッスンします。

http://127.0.0.1:8080 / api / @ / ui を参照して、基本的なUIを確認できます。

/ @ / で始まるルートは、RESTXの予約済みパスである管理コンソールに使用されます。

管理コンソールにログインするには、デフォルトのユーザー名「adminとアプリの作成時に指定したパスワードを使用できます。

コンソールを試す前に、コードを調べて、ウィザードが何を生成したかを理解しましょう。

6. RESTXリソース

ルートは<で定義されています main_package> .rest.HelloResource クラス:

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

RESTXがセキュリティとRESTバインディングにデフォルトのJ2EEアノテーションを使用していることはすぐにわかります。 ほとんどの場合、依存性注入に独自のアノテーションを使用します。

RESTXは、メソッドパラメータをリクエストにマッピングするための多くの妥当なデフォルトもサポートしています。

また、これらの標準アノテーションに加えて、 @RestxResource があり、これは、RESTXが認識するリソースとして宣言します。

ベースパスはに追加されます src / main / webapp / WEB-INF/web.xml。 私たちの場合、それは / api 、GETリクエストをに送信できます http:// localhost:8080 / api / message 、適切な認証を前提としています。

Message クラスは、RESTXがJSONにシリアル化する単なるJavaBeanです。

ブートストラッパーによって生成されたHELLO_ROLEを使用して、 RolesAllowed アノテーションを指定することにより、ユーザーアクセスを制御します。

7. モジュールクラス

前述のように、RESTXは @Named などのJ2EE標準の依存性注入アノテーションを使用し、必要に応じて独自のアノテーションを考案します。おそらく、@ModuleおよびのDaggerフレームワークからヒントを得ます。 ]@Provides。

これらを使用して、アプリケーションのメインモジュールを作成します。このモジュールは、特に管理者パスワードを定義します。

@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 は、Daggerの@ModuleやSpringの@Configurationと同様に、他のコンポーネントを定義できるクラスを定義します。

@Provides は、Daggerの@ProvidesやSpringの@Beanのように、プログラムでコンポーネントを公開します。

そして最後に、 @Named アノテーションを使用して、生成されたコンポーネントの名前を示します。

AppModule は、クライアントに送信されるコンテンツに署名するために使用されるSignatureKeyも提供します。 たとえば、サンプルアプリのセッションを作成するときに、設定されたキーで署名されたCookieが設定されます。

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

詳細については、RESTXのコンポーネントのファクトリ/依存性注入のドキュメントを確認してください。

8. ランチャークラス

最後に、 AppServer クラスを使用して、組み込みのJettyサーバーで標準のJavaアプリとしてアプリケーションを実行します。

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

ここでは、開発フェーズで dev モードを使用して、開発フィードバックループを短縮する自動コンパイルなどの機能を有効にします。

アプリをwar(Webアーカイブ)ファイルとしてパッケージ化して、スタンドアロンのJ2EEWebコンテナーにデプロイできます。

次のセクションでアプリをテストする方法を見つけましょう。

9. 仕様を使用した統合テスト

RESTXの強力な機能の1つは、「仕様」の概念です。 サンプルspecは次のようになります。

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

テストは、YAMLファイル内のGiven-When-Then構造で記述されます。この構造は、APIが特定のリクエスト( then )にどのように応答するかを基本的に定義します( when )システムの現在の状態が与えられた場合(が与えられた)。

src / test /resourcesHelloResourceSpecTestクラスは、上記の仕様で記述されたテストをトリガーします。

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

RestxSpecTestsRunner クラスは、カスタムJUnitランナーです。 これには、次のカスタムJUnitルールが含まれています。

  • 組み込みサーバーをセットアップする
  • システムの状態を準備します(仕様の give セクションに従って)
  • 指定されたリクエストを発行し、
  • 期待される応答を確認する

@FindSpecsIn アノテーションは、テストを実行する対象となるスペックファイルのパスを指します。

この仕様は、統合テストの記述とAPIドキュメントでの例の提供に役立ちます。仕様は、HTTPリクエストのモックとリクエスト/レスポンスのペアの記録にも役立ちます。

10. 手動テスト

HTTPを介して手動でテストすることもできます。 最初にログインする必要があります。これを行うには、RESTXコンソールで管理者パスワードをハッシュする必要があります。

hash md5 <clear-text-password>

そして、それを /sessionsエンドポイントに渡すことができます。

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

(Windowsユーザーは最初にダウンロードカールする必要があることに注意してください。)

そして今、 / message リクエストの一部としてセッションを使用する場合:

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

次に、次のようなものが得られます。

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

11. 管理コンソールの探索

管理コンソールは、アプリを制御するための便利なリソースを提供します。

http://127.0.0.1:8080/admin/@/ui にアクセスして、主な機能を見てみましょう。

11.1. APIドキュメント

APIドキュメントセクションには、すべてのオプションを含むすべての利用可能なルートが一覧表示されます。

そして、個々のルートをクリックして、コンソール自体で試すことができます。

11.2. モニタリング

JVMメトリクスセクションには、アクティブなセッション、メモリ使用量、およびスレッドダンプを含むアプリケーションメトリクスが表示されます。

アプリケーションメトリクスには、デフォルトで監視される要素の主に2つのカテゴリがあります。

  • BUILD は、アプリケーションコンポーネントのインスタンス化に対応します
  • HTTP は、RESTXによって処理されるHTTP要求に対応します

11.3. 統計

RESTXを使用すると、ユーザーはアプリケーションで匿名の統計を収集して共有し、RESTXコミュニティに情報を提供することを選択できます。 restx-stats-adminモジュールを除外することで簡単にオプトアウトできます。

統計は、基盤となるOSやJVMバージョンなどを報告します。

このページには機密情報が表示されるため、構成オプションを確認してください。

これらとは別に、管理コンソールも役立ちます。

  • サーバーログを確認する(ログ)
  • 発生したエラーを表示する(エラー)
  • 環境変数を確認してください(Config)

12. 承認

RESTXエンドポイントはデフォルトで保護されています。つまり、エンドポイントの場合は次のようになります。

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

認証なしで呼び出されると、デフォルトで401が返されます。

エンドポイントを公開するには、メソッドレベルまたはクラスレベルで@PermitAllアノテーションを使用する必要があります。

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

クラスレベルでは、すべてのメソッドがパブリックであることに注意してください。

さらに、フレームワークでは、@RolesAllowedアノテーションを使用してユーザーロールを指定することもできます。

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

この注釈を使用して、RESTXは、認証されたユーザーに管理者ロールも割り当てられているかどうかを確認します。 管理者ロールのない認証済みユーザーがエンドポイントにアクセスしようとすると、アプリケーションは401ではなく403を返します。

デフォルトでは、ユーザーの役割と資格情報はファイルシステムの個別のファイルに保存されます。

したがって、暗号化されたパスワードを持つユーザーIDは、/data/credentials.jsonファイルに保存されます。

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

また、ユーザーの役割は/data/users.jsonファイルで定義されています。

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

サンプルアプリでは、ファイルはFileBasedUserRepositoryクラスを介してAppModuleにロードされます。

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

StdUserクラスはユーザーオブジェクトを保持します。 カスタムユーザークラスにすることもできますが、JSONにシリアル化できる必要があります。

もちろん、データベースにアクセスするような、別のUserRepository実装を使用することもできます。

13. 結論

このチュートリアルでは、軽量のJavaベースのRESTXフレームワークの概要を説明しました。

フレームワークはまだ開発中であり、それを使用するいくつかの荒削りな部分があるかもしれません。 詳細については、公式ドキュメントをご覧ください。

サンプルのブートストラップされたアプリは、GitHubリポジトリで入手できます。