Newer
Older
notes / REST / resteasy2.md

RESTEasy 2.X

RESTEasy 2.Xは、JAX-RS 1.1に準拠したRESTサーバおよび、JAX-RS 1.1で標準化されていないクライアントの独自実装を提供するJBossによるライブラリ。

クライアントの実装

RESTEasyは、クライアントの実装として以下の2通りの実装を提供している。

  • クライアントプロキシー
    • RESTサーバを構築する際に作成したインタフェースを利用してプロキシーを作成し実行
  • マニュアルAPI
    • 通常のリクエストを発行するイメージ
    前者はシンプルではあるが応用がきかないため、後者のマニュアルAPIを用いたRESTクライアントについて説明します。

ライブラリ

JAX-RSの実装である以下のライブラリが必要です。

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>2.3.7.Final</version>
    </dependency>

また、RESTサーバとのインタフェースの形式(XML,JSON)にあわせて、以下のライブラリが必要となります。

    <!-- XMLを使用する場合 -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxb-provider</artifactId>
        <version>2.3.7.Final</version>
    </dependency>        
    <!-- JSONを使用する場合(Jackson) -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson-provider</artifactId>
        <version>2.3.7.Final</version>
    </dependency>
    <!-- JSONを使用する場合(Jettison) -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jettison-provider</artifactId>
        <version>2.3.7.Final</version>
    </dependency>

ファイルアップロードを行う場合は、以下のライブラリも必要です。

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-multipart-provider</artifactId>
        <version>2.3.7.Final</version>
    </dependency>

JBoss EAP 6.X での利用

JBoss EAP 6.Xでは、RestEasy 2.3.7.Finalがモジュールとして提供されており、自動的にロードされるため、WARにライブラリとして含める必要はありません。ただし、下記のモジュールは自動的にロードされないため、 jboss-deployment-structure.xml に記述が必要です。

  • org.jboss.resteasy.resteasy-crypto
  • org.jboss.resteasy.jose-jwt
  • org.jboss.resteasy.resteasy-jettison-provider
  • org.jboss.resteasy.resteasy-yaml-provider
  • org.jboss.resteasy.skeleton-key

マニュアルAPIの基本

リクエスト org.jboss.resteasy.client.ClientRequest を組み立て実行し、レスポンスを取得します。 http://localhost:8080/api/p にGETでアクセスするには、次のように行います。

    // リクエストの生成
    ClientRequest request = new ClientRequest("http://localhost:8080/api/p")
            // レスポンスはJSON形式で取得
            // ACCEPTヘッダに"application/json"を設定
            .accept(MediaType.APPLICATION_JSON);
    // GETでリクエストを送信
    // エンティティの型を指定する。Listの場合は、GenericTypeを使用する。
    ClientResponse<List<Plugin>> response 
            = request.get(new GenericType<List<Plugin>>() {});                
    // レスポンスのステータスコードがOKの場合        
    if (response.getStatus() == 200) {       
        // エンティティを取得
        List<Plugin> plugins = response.getEntity();                          
        for (Plugin plugin : plugins) {
            LOG.info(plugin.toString());
        }
    }

パス・パラメータ

http://localhost:8080/api/p/1 にアクセスする場合、リクエストのURL指定にパス・パラメータを使用することができます。

    // リクエストの生成
    ClientRequest request
        // URLにパス・パラメータidを使用
        = new ClientRequest("http://localhost:8080/api/p/{id}")
        // idの値を設定
        .pathParameter("id", 1)
        .accept(MediaType.APPLICATION_JSON);

クエリー・パラメータ

http://localhost:8080/api/p?name=emma のように、クエリー・パラメータを使用する場合を以下に示します。

    // リクエストの生成
    ClientRequest req 
            = new ClientRequest("http://localhost:9999/api/p")
            // クエリー・パラメータの設定
            .queryParameter("name", "emma")
            // レスポンスはJSON形式で取得
            .accept(MediaType.APPLICATION_JSON);

POST/PUT/DELETE

今まではGETメソッドでしたが、新しいPluginの情報をJSON形式でPOSTし登録してみます。

    // 登録するエンティティを生成
    Plugin p  = new Plugin();                                                      
    p.setName("Emma Plugin");
    p.setDescription("Coverage Plugin");
    // リクエストの生成
    ClientRequest request = new ClientRequest("http://localhost:8080/api/p/");
            .accept(MediaType.APPLICATION_JSON)
            // 登録するエンティティをBODYに設定し、形式(JSON)を指定する
            // Content-Typeヘッダに"application/json"が設定される
            .body(MediaType.APPLICATION_JSON, p);                                   

    // リクエストの送信
    ClientResponse<Plugin> response = request.post(Plugin.class);                  
    // レスポンスのステータスコードを確認
    if (response.getStatus() == 201) {                                             
        Plugin plugin = response.getEntity();
        LOG.info("created! {}", plugin.toString());
    }

PUT/DELETEについても、同様に request#put , request#delete を使用します。

ClientExecutor

RESTサーバとのHTTP通信は、 ClientExecutor により実行しますが、 以下の3つの実装のいずれかを使用することができます。デフォルトは、 ApacheHttpClient4Executor です。

ClientExecutor を変更するには、 ClientRequest のコンストラクタの第2引数に指定します。

    URLConnectionClientExecutor executor = new URLConnectionClientExecutor();
    ClientRequest req = new ClientRequest("http://localhost:8080/api/p", executor);

マルチスレッドでのアクセス

デフォルトの ClientExecutor の実装である ApacheHttpClient4Executor が使用する org.apache.http.impl.conn.SingleClientConnManager は、マルチスレッドに対応しておらず、マルチスレッドから同時にアクセスした場合、シリアルに処理されるため性能が劣化します。

次のように、マルチスレッドに対応した ClientExecutor を使用するようにしてください。

    // マルチスレッドに対応したマネージャを生成
    ClientConnectionManager cm = new ThreadSafeClientConnManager();       
    HttpClient httpClient = new DefaultHttpClient(cm);
    // マルチスレッドに対応したClientExecutorを生成
    ClientExecutor executor = new ApacheHttpClient4Executor(httpClient);
    // ClientExecutorを差し換え
    ClientRequest req
            = new ClientRequest("http://localhost:8080/api/p", executor);

プロキシー

RESTサーバとの通信で、HTTPプロキシーを使用する場合の例を以下に示します。

  // ClientExecutorを生成
    ClientConnectionManager cm = new ThreadSafeClientConnManager();             
    DefaultHttpClient httpClient = new DefaultHttpClient(cm);
    ClientExecutor executor = new ApacheHttpClient4Executor(httpClient);
    // Proxyを設定
    HttpHost proxy = new HttpHost("132.222.121.98", 8080);                      
    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);  

    ClientRequest req
            = new ClientRequest("http://ci.buildria.com/job/aqutils/api/json", executor);

BASIC認証

BASIC認証が必要な場合の例を以下に示します。

    AuthCache authCache = new BasicAuthCache();
    BasicScheme basicScheme = new BasicScheme();
    authCache.put(new HttpHost("localhost", 9999), basicScheme);
    BasicHttpContext localContext = new BasicHttpContext();
    localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

    ClientConnectionManager cm = new ThreadSafeClientConnManager();
    DefaultHttpClient httpClient = new DefaultHttpClient(cm);
    httpClient.getCredentialsProvider().setCredentials(new AuthScope("localhost", 9999),
            new UsernamePasswordCredentials("admin", "adminpasswd"));
    ClientExecutor executor = new ApacheHttpClient4Executor(httpClient, localContext);

ファイルアップロード

    // クライアントの生成
    ClientRequest request = new ClientRequest("http://localhost:8080/b/upload");
    // アップロードファイルの設定
    MultipartFormDataOutput form = new MultipartFormDataOutput();
    form.addFormData("file", getClass().getResourceAsStream("sample.png"),
            MediaType.APPLICATION_OCTET_STREAM_TYPE);
    // リクエストに設定
    request.body(MediaType.MULTIPART_FORM_DATA_TYPE, form);
    // リクエスト送信
    ClientResponse<String> response = request.post(String.class);

その他

  • コネクションタイムアウトの設定
    HttpParams params = httpClient.getParams();
    HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
  • ソケットタイムアウトの設定
    HttpParams params = httpClient.getParams();
    HttpConnectionParams.setSoTimeout(params, 30 * 1000);
  • ユーザエージェントの設定
    // ユーザエージェントを設定
    params.setParameter(CoreProtocolPNames.USER_AGENT, "HogeHoge");
    // ユーザエージェントを削除
    params.removeParameter(CoreProtocolPNames.USER_AGENT);
  • リダイレクト対応

RESTサーバが、ステータスコード 301か302を返した場合に、自動的にリダイレクト先に対応します。

    ClientRequest req = new ClientRequest("http://localhost:9999/api/p", executor);
    req.followRedirects(true);