JAX-RS (Jersey) - URL の拡張子でレスポンスのコンテンツタイプを切り替える

複数のフォーマット (XML とか JSON とか) で返せる REST-API を作る場合、
JAX-RS では Accept リクエストヘッダで
コンテンツタイプを指定して切り替える仕組みになってる。

けどリクエストヘッダを付けるより、
URL 末尾に “.xml” とか “.json” とか付ける方が楽だなーと思ったのでやってみた。

*JAX-RS 標準仕様ではないので、 Jersey 以外では別の方法になると思う。

UriConnegFilter

Jersey では org.glassfish.jersey.server.filter.UriConnegFilter で楽に実現できた。
拡張子とコンテンツタイプを事前にマッピングしておけば、
Accept ヘッダを書き換えてくれるっぽい。

ちなみに Conneg は Content negotiation の略だと思う。
いつも Config に空目してしまう。

URL 拡張子とコンテンツタイプのマッピング方法

ここでは、

  • “.xml” => “application/xml”
  • “.json” => “application/json”

にマッピングしてみる。

マッピング方法は2つあった。
どちらの方法も UriConnegFilterregister は自動でやってくれる。

ResourceConfig のサブクラスでやる方法

org.glassfish.jersey.server.ResourceConfig サブクラスのコンストラクタに、
こんなノリで書けば OK。

public class TryRestApplication extends ResourceConfig {
  public TryRestApplication() {
    packages(TryRestApplication.class.getPackage().getName());
    // URL拡張子とコンテンツタイプのマッピング
    Map<String, MediaType> mappings = new HashMap<>();
    mappings.put("xml", MediaType.APPLICATION_XML_TYPE);
    mappings.put("json", MediaType.APPLICATION_JSON_TYPE);
    property(ServerProperties.MEDIA_TYPE_MAPPINGS, mappings);
  }
}

web.xml に書く方法

org.glassfish.jersey.servlet.ServletContainerinit-param で設定。
jersey.config.server.mediaTypeMappings にカンマ区切りで書けば OK だった。

<filter>
  <filter-name>servlet-container</filter-name>
  <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
  <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>tryrest.TryRestApplication</param-value>
  </init-param>
  <!-- URL拡張子とコンテンツタイプのマッピング -->
  <init-param>
    <param-name>jersey.config.server.mediaTypeMappings</param-name>
    <param-value>
      xml : application/xml,
      json: application/json
    </param-value>
  </init-param>
</filter>

個人的には ResourceConfig で書く方が好き。
パラメータ名やメディアタイプに定数使えるし。

試してみる

以前の記事で書いたコードを流用して試してみる。

GlassFish + JAX-RS (Jersey) で REST なアプリを作ってみる (Java)

Accept ヘッダを付けなくていいので、ブラウザでも簡単に確認できた。

まずは “.json” で GET。

$ curl -i http://localhost:8080/try-rest/hoges/2.json
HTTP/1.1 200 OK
Server: GlassFish Server Open Source Edition  4.1
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)
Content-Type: application/json
Date: Sun, 16 Nov 2014 09:43:09 GMT
Content-Length: 61

{"integer":2,"string":"bbb","strings":["BBB1","BBB2","BBB3"]}

次は “.xml” で GET。

$ curl -i http://localhost:8080/try-rest/hoges/2.xml
HTTP/1.1 200 OK
Server: GlassFish Server Open Source Edition  4.1
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)
Content-Type: application/xml
Date: Sun, 16 Nov 2014 09:43:40 GMT
Content-Length: 185

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><hogeData><integer>2</integer><string>bbb</string><strings>BBB1</strings><strings>BBB2</strings><strings>BBB3</strings></hogeData>

言語も出来るみたい

試してはいないけど、ドキュメント見た感じだと
“Accept-Language” のマッピングも同じように出来そうだった。

まとめ

  • 拡張子でコンテンツタイプを切り替える場合は UriConnegFilter を使う。
  • マッピングは ResourceConfig サブクラス or web.xml で設定。

コード (GitHub)

Release rbox-20141118 - akihyro/try-jaxrs

参考