1. 概要

RESTパラダイムはかなりの数年前から存在しており、今でも多くの注目を集めています。

RESTful APIは、さまざまな方法でJavaに実装できます。Spring、JAX-RSを使用することも、十分に勇気がある場合は、独自のベアサーブレットを作成することもできます。 必要なのはHTTPメソッドを公開する機能だけです。残りは、HTTPメソッドを整理する方法と、APIを呼び出すときにクライアントをガイドする方法です。

タイトルからわかるように、この記事ではJAX-RSについて説明します。 しかし、「単なるAPI」とはどういう意味ですか? ここでの焦点は、JAX-RSとその実装の間の混乱を明確にし、適切なJAX-RSWebアプリがどのように見えるかの例を提供することにあることを意味します。

2. JavaEEへの組み込み

JAX-RSは、Java EEによって提供される仕様、一連のインターフェース、およびアノテーションにすぎません。 そしてもちろん、実装もあります。 よく知られているのは、RESTEasyJerseyです。

また、JEE準拠のアプリケーションサーバーを構築することを決定した場合、Oracleの担当者は、とりわけ、サーバーがデプロイされたアプリが使用するJAX-RS実装を提供する必要があることを教えてくれます。 そのため、Java Enterprise Edition Platformと呼ばれています。

仕様と実装のもう1つの良い例は、JPAHibernateです。

2.1. 軽量戦争

では、これらすべてが開発者にとってどのように役立つのでしょうか。 ヘルプは、デプロイ可能なものを非常に薄くすることができ、非常に薄くする必要があるため、アプリケーションサーバーが必要なライブラリを提供できるようにすることです。 これは、RESTful APIを開発する場合にも当てはまります。最終的なアーティファクトには、使用されているJAX-RS実装に関する情報が含まれていてはなりません。

もちろん、実装を提供することはできます(ここのRESTeasyのチュートリアル)。 しかし、その場合、アプリケーションを「JavaEEアプリ」と呼ぶことはできなくなります。 明日誰かが来て、「 OK、GlassfishまたはPayaraに切り替えるとき、JBossが高すぎる!」と言ったら、それはできるかもしれませんが、簡単な仕事ではありません。

独自の実装を提供する場合は、サーバーが独自の実装を除外することを確認する必要があります。これは通常、デプロイ可能な内部に独自のXMLファイルを含めることで発生します。 言うまでもなく、このようなファイルには、3年前に会社を辞めた開発者を除いて、誰も知らないあらゆる種類のタグと命令が含まれている必要があります。

2.2. サーバーを常に知っている

これまで、提供されているプラットフォームを利用する必要があると述べてきました。

使用するサーバーを決定する前に、少なくとも実稼働環境で、サーバーが提供するJAX-RS実装(名前、ベンダー、バージョン、および既知のバグ)を確認する必要があります。 たとえば、GlassfishにはJerseyが付属していますが、WildflyまたはJbossにはRESTEasyが付属しています。

もちろん、これは調査に少し時間がかかることを意味しますが、プロジェクトの開始時または別のサーバーへの移行時に1回だけ実行されることになっています。

3. 例

JAX-RSでのプレイを開始する場合、最短パスは次のとおりです。pom.xmlに次の依存関係を持つMavenwebappプロジェクトがあります。

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>

JavaEE 7を実装しているアプリケーションサーバーがすでにたくさんあるので、JavaEE7を使用しています。 そのAPIjarには、パッケージjavax.ws.rsにある使用する必要のあるアノテーションが含まれています。 スコープが「提供」されるのはなぜですか? このjarは最終ビルドにもある必要がないため、コンパイル時に必要であり、実行時にサーバーによって提供されます。

依存関係を追加した後、最初にエントリクラスを作成する必要があります。 javax.ws.rs.core.Application を拡張し、javax.ws.rs.ApplicationPathで注釈が付けられた空のクラスです。

@ApplicationPath("/api")
public class RestApplication extends Application {
}

エントリパスを次のように定義しました /api。 リソースに対して宣言する他のパスが何であれ、それらには接頭辞が付けられます / api

次に、リソースを見てみましょう。

@Path("/notifications")
public class NotificationsResource {
    @GET
    @Path("/ping")
    public Response ping() {
        return Response.ok().entity("Service online").build();
    }

    @GET
    @Path("/get/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getNotification(@PathParam("id") int id) {
        return Response.ok()
          .entity(new Notification(id, "john", "test notification"))
          .build();
    }

    @POST
    @Path("/post/")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response postNotification(Notification notification) {
        return Response.status(201).entity(notification).build();
    }
}

アプリが実行されているかどうかを呼び出して確認するための単純なpingエンドポイント、通知のGETとPOSTがあります(これは、属性にゲッターとセッターを加えたPOJOです)。

この戦争をJEE7を実装するすべてのアプリケーションサーバーに展開すると、次のコマンドが機能します。

curl http://localhost:8080/simple-jaxrs-ex/api/notifications/ping/

curl http://localhost:8080/simple-jaxrs-ex/api/notifications/get/1

curl -X POST -d '{"id":23,"text":"lorem ipsum","username":"johana"}' 
  http://localhost:8080/simple-jaxrs-ex/api/notifications/post/ 
  --header "Content-Type:application/json"

ここで、simple-jaxrs-exはwebappのコンテキストルートです。

これは、Glassfish4.1.0およびWildfly9.0.1.Finalでテストされました。 this のバグのため、最後の2つのコマンドはGlassfish4.1.1では機能しないことに注意してください。 このGlassfishバージョンでは、JSONのシリアル化に関して、明らかに既知の問題です(このサーバーバージョンを使用する必要がある場合は、JSONマーシャリングを自分で管理する必要があります)

4. 結論

この記事の最後で、JAX-RSは強力なAPIであり、必要なもののほとんど(すべてではないにしても)はすでにWebサーバーによって実装されていることを覚えておいてください。 デプロイ可能なライブラリを管理できないライブラリの山に変える必要はありません。

この記事は簡単な例を示しており、事態はさらに複雑になる可能性があります。 たとえば、独自のマーシャラーを作成することができます。 それが必要な場合は、Jersey、Resteasy、またはその他の具体的な実装ではなく、JAX-RSの問題を解決するチュートリアルを探してください。 問題は1つまたは2つの注釈で解決できる可能性が非常に高いです。