JavaでRESTクライアントを作成する【第一回】

REST

Java で REST リクエストを送信するための方法に関して記します。
REST リクエストの送信を行うにあたっては、Jersey 1.x 系を利用します。

2014/09/04 コードに一部誤りがあったため修正しました。

はじめに

「妊活」 というキーワードを 「妖活」 と見間違え、「妖怪ウォッチのグッズ獲得するためにみんな頑張ってるのはしってたけど、そんな言葉まで!」 と思った今日この頃、みなさまいかがお過ごしですか。

ちなみにうちの子も好きで見てはいますが、メダルコレクターにはなっていません。

 

ここ暫く Magnolia CMS の REST API を利用した、コンテンツの移行を試していました。
とある問題で "どはまり" したのですが、ようやく道が開けそうになってきたので、これに関連して Java で REST リクエストを送信する方法に関して書きます。

第一回はとりあえず「GETリクエストを送信する」ところまでです。

※写真は IM FREE から ( shackles by Wonderlane )

環境

REST を利用するにあたって クライアント ( REST リクエストを送信するプログラム ) の実装には Java、及び、Jersey (1.x系) を利用します。

Jersey は既に 2.x 系になっていますが、1.x 系の方が使い慣れているためこちらを利用します ( ツールを想定したクライアントの実装であるため、最新版でなくても構わないという理由もある )。

※Jersey は JAX-RS のリファレンス実装

実際にコード作成して、動作を確認した環境は以下になります。
Java は1.7 以上、Jersey は 1.x 系であれば、おそらく動作すると思います。

Java 1.7.0_55
Jersey 1.18.1

ライブラリの取得

私が実装した際には、maven を利用して以下の dependency 設定を行っています

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.18.1</version>
        </dependency>

maven を利用していない場合、Jersey のダウンロードページ からライブラリを取得する等して下さい。

REST クライアントを作成する

Jersey を利用して REST クライアントを実装します。

先ずは、RESTful なWebサービスで一般的に利用される以下のリクエスト処理を行うためのクラスを作成する事にします。

HTTPメソッド操作内容
GETリソース取得
PUTリソース作成
POSTリソース更新
DELETEリソース削除

RestClient クラスの作成

先ず RestClient クラスを作成します。

ここで作成するクライアントは最終的には Magnolia CMS の REST API を操作するために利用しますが、その際、処理内容によっては認証を行う必要があります。
Magnolia の REST API では 基本認証での認証をサポートしています。ここで作成するクラスでも基本認証を行うようにクラスを作成します。

参考 : REST API - Magnolia CMS

RestClient.java

package jp.co.agilegroup.rest;

import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * RESTリクエストを行うためのクライアントクラス
 * @author masao.suda
 */
public class RestClient {

    private String account = null;
    private String password = null;
    
    public RestClient(String account, String password) {
        this.account = account;
        this.password = password;
    }
    
    private Client getClient() {
        Client client = new Client();
        client.addFilter(new HTTPBasicAuthFilter(account, password));
        return client;
    }
}

com.sun.jersey.api.client.Client クラスは Jersey 1.x における RESTクライアントの実装になります。
HttpBasicAuthFilter クラスを利用して 基本認証を行うようにします。

※ 基本認証が不要な場合、addFilter 処理は不要です。

GET 処理の実装

次に GETメソッド でのリクエスト処理を実装します。

RESTful Web サービスにおける GET メソッドは、リソースの取得のために利用されます。
リソースには固有の1つ以上のURIが割り当てられており、このURIに対してGET リクエストを送信する事でリソースが取得できます。

リソースの種類として最も多いのは HTML、XML、JSON 等のテキストデータです。

これらテキスト(文字列)データを取得するメソッドを示します ( 上記RestClientクラスに追記して下さい )。

RestClient.java - getString

    public String getString(String url, MediaType type) {
        Client client = getClient();
        WebResource resource = client.resource(url);
        ClientResponse response = resource.accept(type).get(ClientResponse.class);
        switch (response.getStatus()) {
        case 200 :  // OK
            break;
        default:
            return String.format("Code:%s Entity:%s",
                    response.getStatus(),
                    response.getEntity(String.class));
        }
        return response.getEntity(String.class);
    }

上記メソッドでは、MediaType パラメータを渡すようにしていますが、この値は HTTPリクエストの Acceptヘッダに設定されます。
Webサービス側の実装次第ですが、Acceptヘッダの値を見て、"application/xml" ならば xml、 "application/json" ならば json を返すようなWebサービスも存在しますので、こういったサービスを利用する場合パラメータ化しておいた方が便利です。

また、HTTPステータスコードによって処理を分岐しています。
GETリクエストが正常終了した場合のステータスコードは 200 (OK) です。
これ以外のステータスコードが返された場合には、ステータスコード、及び、HTMLボディの内容を返すようになっています。

RestClient の利用

ここまで作成した上記 RestClient クラスを利用して GETリクエストを送信してみます。

RestTest.java

package jp.co.agilegroup.rest;

import javax.ws.rs.core.MediaType;

public class RestTest {
    public static void main(String[] args) {
        RestClient client = new RestClient("admin", "admin");
        String uri = "http://....";    // 実際のリクエスト先を指定

        String xml = client.getString(uri, MediaType.APPLICATION_XML_TYPE);
        System.out.println(xml);
        
        String json = client.getString(uri, MediaType.APPLICATION_JSON_TYPE);
        System.out.println(json);
    }
}

GETリクエストを送信する場合、上記のようなコードを記述すればOKです。

このコードでは Accept ヘッダに "application/xml"、及び、"application/json" を設定したGETリクエストの送信を行います。
サービスがサポートしていれば、それぞれで XML形式、及び、JSON形式のリソースが取得できるはずです。

※実際 Jersey (サーバ側) では、Acceptヘッダの値に応じて XML/JSON双方のデータを返すという実装も可能になっています。

Magnolia CMS の REST API に対してGET リクエストを送信したところ、以下のような結果になりました。

URIhttp://localhost:8080/magnoliaAuthor/.rest/nodes/v1/website/demo-project
リソース(application/xml)<?xml version="1.0" encoding="UTF-8" standalone="yes"?><node><identifier>1be12547-ad82-4c83-8396-213466ceb003</identifie r><name>demo-project</name><nodes/><path>/demo-project</path><properties><property><multiple>false</multiple><name>logoI mg</name><type>String</type><values><value>jcr:a1918662-8cbe-4346-ac5a-1b24a9950e2b</value></values></property><property ><multiple>false</multiple><name>title</name><type>String</type><values><value>Home</value></values></property><property ><multiple>false</multiple><name>searchUUID</name><type>String</type><values><value>e301b5fc-275d-440a-8e98-17cba32c29c3 </value></values></property><property><multiple>false</multiple><name>hideInNav</name><type>Boolean</type><values><value >false</value></values></property><property><multiple>false</multiple><name>printLogoImg</name><type>String</type><value s><value>jcr:7240d7f5-4d10-4f56-a944-7864cfb77f5b</value></values></property><property><multiple>false</multiple><name>s iteTitle</name><type>String</type><values><value>Demo Project</value></values></property></properties><type>mgnl:page</t ype></node>
リソース(application/json){"name":"demo-project","type":"mgnl:page","path":"/demo-project","identifier":"1be12547-ad82-4c83-8396-213466ceb003","pr operties":[{"name":"logoImg","type":"String","multiple":false,"values":["jcr:a1918662-8cbe-4346-ac5a-1b24a9950e2b"]},{"n ame":"title","type":"String","multiple":false,"values":["Home"]},{"name":"searchUUID","type":"String","multiple":false," values":["e301b5fc-275d-440a-8e98-17cba32c29c3"]},{"name":"hideInNav","type":"Boolean","multiple":false,"values":["false "]},{"name":"printLogoImg","type":"String","multiple":false,"values":["jcr:7240d7f5-4d10-4f56-a944-7864cfb77f5b"]},{"nam e":"siteTitle","type":"String","multiple":false,"values":["Demo Project"]}],"nodes":[]}

MediaType に "application/xml" を指定した場合でもなぜか json 形式のリソースが取得されました orz
試しに curl で -H "accept:application/xml" を指定してリクエストすると xml 形式のデータが取得されるという。。。(謎)
=> コードに誤りがありました。修正しました。


アイコン認証Webサービスで xml/json をサポートしているリソースに対してリクエストしたら、ちゃんと両方のメディアタイプが取得されたので、MediaType の設定自体は問題ないはずです。

まとめ

今回はとりあえず Jersey を利用して 文字データのリソースを取得するところまでを記載しました。
Jersey のクライアントAPIを利用する事で、簡単にXMLやJSON形式のリソースを取得する事が可能です。

しかし、Javaを利用したプログラムを行う上では、はっきりいって文字列データとして取得できたとしてもあまり嬉しくありません。

実は Jersey のクライアントAPIを利用する事で、取得したデータ ( XML や JSON ) を Javaオブジェクトにマッピングする事が可能です。

次回 はこの方法に関して書こうと思います。