自動生成されたプロジェクトの構造
作成されたフォルダ構成は、通常のmaven-webapp-archetypeに則ったものですが、次表に示すとおり、いくつかのApp Engine用のファイルが追加されています。
追加されたファイル | 意味 |
---|---|
src/main/webapp/WEB-INF/appengine-web.xml | App Engine用の定義ファイル |
eclipse-launch-profiles/DevAppServer.launch | 開発サーバを起動するEclipseの実行構成ファイル |
eclipse-launch-profiles/UpdateApplication.launch | App EngineにデプロイをするためのEclipseの実行構成ファイル |
さらに、pom.xml内にはappengine-maven-plugin
という、App Engineに関する操作を行うためのプラグインの依存関係も追記されています。今回使用するCloud Endpointsに関する機能も、このプラグインを使用します。
このプラグインはApp Engineに関する様々な操作をゴール(goal)として提供しており、次のようなmavenコマンドを実行することで、全てのゴールを確認できます。
mvn help:describe -Dplugin=com.google.appengine:appengine-maven-plugin
Cloud Endpointsのための設定情報
作成されたプロジェクトには、通常のmaven-webapp-archetypeにApp Engineの設定が追加されていました。それだけではなく、Cloud Endpointsの設定もsrc/main/webapp/WEB-INF/web.xml
に追加されています。
<servlet> <servlet-name>SystemServiceServlet</servlet-name> <servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class> <init-param> <param-name>services</param-name> <param-value>com.shin1ogawa.YourFirstAPI</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SystemServiceServlet</servlet-name> <url-pattern>/_ah/spi/*</url-pattern> </servlet-mapping>
SystemServiceServlet
というサーブレットクラスの定義が追加されていますが、これがCloud Endpointsの機能を担い、/_ah/spi/
から始まるパスへのリクエストが届いたときに、このサーブレットクラスがリクエストを受け取る設定になっています。
SystemServiceServlet
のinit-param
要素に定義されているservices
というパラメータには"YourFirstAPI"というAPIクラスが設定されていますが、ここに記述されたクラスがAPIクラスになります。開発者がAPIを作成した場合は、このservices
パラメータにもAPIクラスを追加していくことになります(カンマ区切りで複数のクラスを設定できます)。
APIを実装する
それでは、APIを1つ実装してみましょう。
データを保持するモデルクラスを作成する
まずは、サーバ側で何かのデータを保存することを想定し、モデルクラスを1つ作成します。このモデルクラスは、id、message、createdAtというフィールドと、それらへのアクセサを持つPOJOにします。クライアントからmessageを受け取り、idとcreatedAtをサーバ側で設定する想定です。
public class MyModel { String id; String message; Date createdAt; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } }
Cloud Endpointsでは、JSONとJavaクラスの変換に「Jackson」を使用していますが、Jacksonの機能であるJsonSerializer
やJsonDeserializer
は使えません。ですので、値を変換したいフィールドや通信に含めたくないフィールドを持つPOJOを使う場合には、APIのインタフェースとして使用するCloud Endpoints用のモデルクラスを別途作り、本来のモデルクラスと変換してやる必要があります。
APIクラスを実装する
次に、先ほど作成したモデルクラスを使ってデータをやりとりするためのAPIクラスを実装します。先に説明したとおり、Cloud Endpointsで使用するAPIクラスはweb.xml
の設定でSystemServiceServlet
に認識させる必要がありますが、maven-archetype:generate
でプロジェクトを生成すると"YourFirstAPI"というクラスが自動生成され、さらにSystemServiceServlet
に認識されるようweb.xml
に登録されるので、それをそのまま利用します。
Cloud Endpointsで使用するAPIクラスは@Api
アノテーションで修飾する必要があります。元々作成されていた"YourFirstAPI"クラスを開き、@Api
アノテーションで修飾します。また、このアノテーションには、APIの名前とバージョンを示すname
とversion
パラメータが必要です。
@Api(name = "myFirstAPI", version = "v1") public class YourFirstAPI { }
APIのメソッド名は、Google APIの慣例にならい、データ追加用メソッドをinsert
、データの一覧取得用メソッドをlist
とすることにします。
また、Cloud Endpointsで使用するAPIのメソッドは@ApiMethod
アノテーションで修飾する必要があります。APIメソッドの名前と対応するパスを示すname
,とpath
パラメータも必要です。
なお、作成しているのは学習用のサンプルアプリケーションですから、実装をシンプルにするためにデータベースなどは使用せず、データはstatic変数に保持するようにしています。
static ConcurrentHashMapmyModels = new ConcurrentHashMap<>(); @ApiMethod(name = "myFirstAPI.insert", path = "myFirstAPI/insert") public MyModel insert(MyModel myModel) { Date now = new Date(); myModel.setId(String.valueOf(now.getTime())); myModel.setCreatedAt(now); myModels.put(myModel.getId(), myModel); return myModel; } @ApiMethod(name = "myFirstAPI.list", path = "myFirstAPI/list") public List list() { return new ArrayList<>(myModels.values()); }