まずはRESTfulアプリケーションのおさらい
RESTとは、REpresentational State Transfer の略でWebアプリケーションの設計思想です。RESTfulとは、REST の規約に従ったWebサービスのことです。
RESTで大事なのは、
- リソース指向
- 統一インターフェース
- ステートレス
という点です。
リソース指向
サービスを提供するために、システムのリソースをAPIを通して公開します。このAPIはURIのパスになります。**URIのパス名はとっても重要です。**パス名の良し悪しがサービスの良し悪しになります。
リソースの意味が直感的に分かるように名詞を付けていきます。より特定な情報をやり取りする場合は階層を用います。パスは短く簡潔にし、名詞同士をくっつけたり、名詞と動詞をくっつけたようなパス名にならないようにしましょう。
ブック一覧
[GET]http://exsample.jp/book/
特定のブック
[GET]http://exsample.jp/book/1234
[GET]http://exsample.jp/book/name/書籍名
作成
[PUT]http://exsample.jp/book/
更新
[POST]http://exsample.jp/book/1234
削除
[DELETE]http://exsample.jp/book/1234
NG例
[GET]http://exsample.jp/bookname/書籍名
[DELETE]http://exsample.jp/deletebook/xxx
統一インターフェース
HTTPのメソッドを使ってアクセスします。
メソッド | 役割 |
---|---|
GET | リソースの取得。GETでのアクセスはリソースの内容に影響を与えない |
POST | リソースの新規作成 |
PUT | 既存のリソースの更新 |
DELETE | リソースの削除 |
ステートレス
サーバー側でもっている状態に依らずいつでも同じ意味合いのやり取りが出来ることが大事です。同じ意味合いなので、必ずしも同じ情報とは限りません。価格といった情報は変動しますが、そういった付加情報的なものは変動します。仕組みで云えば、例えばクッキーや隠しパラメータといったURI以外の仕組みを持たないことです。
ところで、セッション情報で権限を持たないロールには限定的な情報しか返さないということはしたことあるけど、これもNGなのかな?
データベース設計
リソースの永続化はRDBだろうとNoSQLだろうとファイルだろうと何でも構いませんが、今回はRDBを扱います。
ORマッパーには
- 先にコードで定義したエンティティクラスからテーブル生成
- 先にデータベースでテーブルを定義し、コードを生成
というどちらかの方法がとれますが、今回は後者の方で進めます。
テーブル設計で大事なのは参照整合性を保つことです。
SQLアンチパターンを読むと詳しく解説されています。テーブル設計で外部結合や制約を適切に活用することで、アプリケーションで余計な実装をしなくても良くなります。ただし、逆の考え方もあって、むやみやたらに参照整合性制約を使わずに、アプリケーション側で参照整合性を保つという手もあります。テーブル設計をガチガチにすると柔軟性が低くなるという理由ですね。Railsなんかはアプリケーション側の責務としていますね。
JavaEEのテクノロジー
JavaEE7で含まれるテクノロジーの一部です。いろいろあって大変そうに見えますが、それぞれがRESTの仕様、ORMの仕様、DIの仕様っていう風に分割統治で役割がはっきりしています。
機能 | 対象領域 | 役割 |
---|---|---|
JSF | プレゼンテーション層 | HTML5対応のWebページのフレームワーク |
WebSocket | サービス公開 | 双方向通信のフレームワーク |
JAX-RS | サービス公開 | RESTのフレームワーク |
JSON-P | 転送 | JSONオブジェクト生成 |
JAXB | 転送 | XMLオブジェクト生成 |
EJB | ビジネス層 | ビジネスロジックに使用。トランザクション管理を備える |
JPA | 永続化層 | ORマッパーフレームワーク |
CDI | 全領域 | DIフレームワーク |
システムの開発環境
今回は以下の環境で構築しますが、好きな組み合わせで構いません。
インストール手順や設定については端折ります。
- OS:Windows
- Java:Java SDK 8u92 64bit
- 統合開発環境:NetBeans 8.1 64bit
- アプリケーションサーバー:Apache TomEE 7.0.0-M3
- データーベース:PostgreSQL 9.4.8 64bit
- JDBCドライバ:JDBC 42 9.4 Build 1208
- プロジェクト管理ツール:Maven 3.3.9
- REST確認ツール:Fiddler
アプリケーションサーバーですが、JavaEE7に対応しているものを選択する必要があります。
Apache TomEE 7はまだ開発版なので、お試しであればGlassFishを使えばよいですが、参照実装なので本番環境では利用できません。また、RESTだけであればJavaEE6でも十分なので、他にもいくつかの選択肢があります。
RESTサービス構築手順
- テーブル定義
- JavaEEプロジェクト作成
- データーベースからエンティティクラス、RESTサービスクラスの作成
基本的な流れはこれだけですね。
NetBeansを使うといろいろ自動化されているので便利です。
ここで3つのクラスが生成されます。
Applicationクラス
@ApplicationPath:アプリケーションをWebサービスに配置する場合のトップパスを設定します。サービスを表す名前をつけましょう。
@javax.ws.rs.ApplicationPath("service")
public class ApplicationConfig extends Application {
:
:
}
Entityクラス
JPAのO/Rマッピングを行うエンティティです。
いくつかのアノテーション定義だけで関連付けができます。
@Enitity、@Table、@Id、@NotnNull、@Column、@Size:データベースと関連付けるための定義
@XmlRootElement:XML/JSONとオブジェクトのシリアライズとデシリアライズを行うための定義
@Entity
@Table(name = "userentity")
@XmlRootElement
public class Userentity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Long id;
@Size(max = 255)
@Column(name = "name")
private String name;
@Size(max = 255)
:
:
}
Restサービスクラス
@Path:リソース名を定義します。クライアントからアクセスする場合は@ApplicationPathと組み合わさり、http://exsample.jp/service/users となります。
@Path("{id}"):リソースに対して更に詳細なアクセスを提供します。
@PathParam("~~~"):パスパラメータを取得します。
@POST、@PUT、@DELETE、@GET:リソースの操作を割り当てます
@Consumes、@Producess:リソースが受け付けるMIMEタイプ、リソースから返されるMIMEタイプを指定します。
@Stateless
@Path("users")
public class UserentityFacadeREST extends AbstractFacade<Userentity> {
@PersistenceContext(unitName = "adtekfuji_TestJavaEE_RESTServer_war_1.0PU")
private EntityManager em;
public UserentityFacadeREST() {
super(Userentity.class);
}
@POST
@Override
@Consumes({"application/xml","application/json"})
public void create(Userentity entity) {
super.create(entity);
}
@PUT
@Path("{id}")
@Consumes({"application/xml","application/json"})
public void edit(@PathParam("id") Long id, Userentity entity) {
super.edit(entity);
}
@DELETE
@Path("{id}")
public void remove(@PathParam("id") Long id) {
super.remove(super.find(id));
}
@GET
@Path("{id}")
@Produces({"application/xml","application/json"})
public Userentity find(@PathParam("id") Long id) {
return super.find(id);
}
@GET
@Override
@Produces({"application/xml","application/json"})
public List<Userentity> findAll() {
return super.findAll();
}
@GET
@Path("{from}/{to}")
@Produces({"application/xml","application/json"})
public List<Userentity> findRange(@PathParam("from") Integer from, @PathParam("to") Integer to) {
return super.findRange(new int[]{from, to});
}
@GET
@Path("count")
@Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
RESTを確認する
Chrome では Advanced REST clientとかDHC REST ClientといったアプリでRESTの確認が出来ますが、アクセスした履歴を残してほしかったり、いろんな形式でデータを見たければ「Fiddler」というツールがお薦めです。Webプロキシとしてのツールなので、HTTP(S)のあらゆる情報が確認できます。