単一の API が特に複雑である場合、複数の Java クラスから実装することもできます。さまざまなクラスを同じ API の一部にするには、次のことが必要です。
- 各クラスに同じ
name
文字列とversion
文字列を、それぞれの@Api
アノテーションで指定します。 - クラス API を
web.xml
にカンマ区切りのリストとして追加します。
たとえば、次の 2 つのクラスはどちらも tictactoe
API の一部です。
@Api(name = "tictactoe", version = "v1")
class TicTacToeA { … }
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
API 構成は @Api
アノテーション プロパティを通じて指定されます。ただし、同じ API に複数のクラスがある場合、@Api
の要件は、各クラスの @Api
アノテーションに単純に同じ name
と version
の文字列を使用するだけではありません。実際、クラスの @Api
プロパティで指定された API 構成に違いが 1 つでも存在する場合、バックエンド API は動作しません。マルチクラス API で各クラスの @Api
プロパティに違いがあると API 構成が「あいまい」になり、App Engine 用の Cloud Endpoints Frameworks では動作しなくなります。
明確なマルチクラスの API を作成するには、いくつかの方法があります。
- 同じ API に含まれるすべてのクラスの
@Api
アノテーションのプロパティが完全に同じであることを手動で確認します。 - Java 継承を介してアノテーション継承を使用します。この継承では、同じ API に含まれるすべてのクラスは、共通の
@Api
アノテーションが付いている基本クラスから同じ API 構成を継承します。 - 同じ API に含まれるすべてのクラスで
@ApiReference
アノテーションによるアノテーション継承を使用することによって、共通の@Api
アノテーションが付いているクラスから同じ API 構成が参照されるようにします。
クラス間で異なるプロパティに対する @ApiClass
の使用
この機能を使用するには、以下をインポートする必要があります。
import com.google.api.server.spi.config.ApiClass;
@Api
アノテーションのすべてのプロパティが API のすべてのクラスで一致している必要がありますが、さらに @ApiClass
アノテーションを使用して、クラス間で完全に同じである必要がないプロパティを指定できます。例:
// API methods implemented in this class allow only "clientIdA".
@Api(name = "tictactoe", version = "v1")
@ApiClass(clientIds = { "clientIdA" })
class TicTacToeA { … }
// API methods implemented in this class provide unauthenticated access.
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
TicTacToeA
では、許可されたクライアント ID が含まれるクライアント ID のホワイトリストを使用してアクセスを制限しますが、TicTacToeB
ではアクセスを制限しません。
@ApiClass
アノテーションで指定するすべてのプロパティには、@Api
アノテーションに同等のプロパティがあります。@Api
内の同等のプロパティが API 全体のデフォルトになります。@Api
で指定された同じプロパティに API 全体のデフォルトがある場合、クラス固有の @ApiClass
プロパティによって API 全体のデフォルトがオーバーライドされます。
次の例では、クラス固有の @ApiClass
のプロパティによって @Api
の同等のプロパティがオーバーライドされます。
// For this class "boards" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "boards")
class TicTacToeBoards { … }
// For this class "scores" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "scores")
class TicTacToeScores { … }
// For this class, the API-wide default "games" is used as the resource.
@Api(name = "tictactoe", version = "v1", resource = "games")
class TicTacToeGames { … }
アノテーション継承
@Api
と @ApiClass
アノテーションのプロパティは他のクラスから継承でき、Java 継承または @ApiReference
継承によって個々のプロパティをオーバーライドできます。
Java 継承の使用
@Api
または @ApiClass
アノテーションで別のクラスを拡張するクラスは、同じプロパティでアノテーションが付けられているかのように動作します。例:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA and TicTacToeB both behave as if they have the same @Api annotation as
// TicTacToeBase
class TicTacToeA extends TicTacToeBase { … }
class TicTacToeB extends TicTacToeBase { … }
アノテーションはインターフェース実装を通じてではなく Java サブクラスによってのみ継承されます。例:
@Api(name = "tictactoe", version = "v1")
interface TicTacToeBase { … }
// Does *not* behave as if annotated.
class TicTacToeA implements TicTacToeBase { … }
したがって、フレームワークのアノテーションの多重継承は一切サポートされません。
継承は @ApiClass
でも有効です。
@ApiClass(resource = "boards")
class BoardsBase { … }
// TicTacToeBoards behaves as if annotated with the @ApiClass from BoardsBase.
// Thus, the "resource" property will be "boards".
@Api(name = "tictactoe", version = "v1", resource = "scores")
class TicTacToeBoards extends BoardsBase { … }
TicTacToeBoards
は、BoardsBase
から resource
プロパティ値 boards
を継承するため、その @Api
アノテーションの resource
プロパティ設定(scores
)を上書きします。いずれかのクラスが @Api
アノテーションで resource プロパティを指定している場合、すべてのクラスの @Api
アノテーションで同じ設定を指定する必要があります。この継承技法により、その @Api
プロパティをオーバーライドできます。
@ApiReference
継承の使用
この機能を使用するには、以下をインポートする必要があります。
import com.google.api.server.spi.config.ApiReference;
@ApiReference
アノテーションは、アノテーションの継承を指定するための代替方法を提供します。@ApiReference
を使用して、@Api
または @ApiClass
アノテーションで別のクラスを指定するクラスは、同じプロパティでアノテーションが付けられているかのように動作します。例:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA behaves as if it has the same @Api annotation as TicTacToeBase
@ApiReference(TicTacToeBase.class)
class TicTacToeA { … }
Java 継承と @ApiReference
の両方が使用されている場合、アノテーションは @ApiReference
アノテーションのみによって継承します。Java 継承によって継承されたクラスの @Api
と @ApiClass
のアノテーションは無視されます。次に例を示します。
@Api(name = "tictactoe", version = "v1")
class TicTacToeBaseA { … }
@Api(name = "tictactoe", version = "v2")
class TicTacToeBaseB { … }
// TicTacToe will behave as if annotated the same as TicTacToeBaseA, not TicTacToeBaseB.
// The value of the "version" property will be "v1".
@ApiReference(TicTacToeBaseA.class)
class TicTacToe extends TicTacToeBaseB { … }
継承された構成のオーバーライド
Java 継承または @ApiReference
のどちらを使用して構成を継承する場合も、新しい @Api
または @ApiClass
のアノテーションを使用して継承された構成をオーバーライドできます。新しいアノテーションで指定された構成プロパティのみがオーバーライドされます。指定されていないプロパティは引き続き継承されます。
例:
@Api(name = "tictactoe", version = "v2")
class TicTacToe { … }
// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@Api(name = "checkers")
class Checkers extends TicTacToe { … }
継承のオーバーライドは、@ApiClass
にも有効です。
@Api(name = "tictactoe", version = "v1")
@ApiClass(resource = "boards", clientIds = { "c1" })
class Boards { … }
// Scores will behave as if annotated with resource = "scores" and clientIds = { "c1" }
@ApiClass(resource = "scores")
class Scores { … }
@ApiReference
を通じて継承する場合もオーバーライドは機能します。
@Api(name = "tictactoe", version = "v2")
class TicTacToe { … }
// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@ApiReference(TicTacToe.class)
@Api(name = "checkers")
class Checkers { … }
@ApiMethod
アノテーションの継承
@ApiMethod
アノテーションを、オーバーライドされたメソッドから継承できます。次に例を示します。
class TicTacToeBase {
@ApiMethod(httpMethod = "POST")
public Game setGame(Game game) { … }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
// setGame behaves as if annotated with the @ApiMethod from TicTacToeBase.setGame.
// Thus the "httpMethod" property will be "POST".
@Override
public Game setGame(Game game) { … }
}
@Api
と @ApiClass
のアノテーションを継承する場合と同様、相互にオーバーライドする複数のメソッドに @ApiMethod
アノテーションがある場合、個々のプロパティをオーバーライドできます。例:
class TicTacToeBase {
@ApiMethod(httpMethod = "POST", clientIds = { "c1" })
public Game setGame(Game game) { … }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
// setGame behaves as if annotated with httpMethod = "GET" and clientIds = { "c1"}.
@ApiMethod(httpMethod = "GET")
@Override
public Game setGame(Game game) { … }
}
メソッドには @ApiReference
アノテーションや同等機能がないため、@ApiMethod
は常に、@ApiReference
ではなく Java 継承によって継承されます。
継承と優先順位のルール
これまでの説明を要約するために、次の表には、継承ルールと優先順位を示しています。
アノテーション / 継承 | ルール |
---|---|
@Api |
すべてのクラスで同じである必要があります。 |
@ApiClass |
@Api のプロパティをオーバーライドするために特定のクラスに指定します。 |
Java 継承 | クラスは基本クラスの @Api と @ApiClass を継承します。 |
@ApiReference |
クラスは参照されるクラスの @Api と @ApiClass を継承します。 |
基本クラスから継承するクラス(Java)での @ApiReference の使用 |
クラスは参照されるクラスの @Api と @ApiClass を継承します。基本クラスからは継承されません。 |
アノテーションの継承の一般的な使用例
継承の典型的な使用例は以下のとおりです。
API バージョン向け
@Api(name = "tictactoe", version = "v1")
class TicTacToeV1 { … }
@Api(version = "v2")
class TicTacToeV2 extends TicTacToeV1 { … }
マルチクラスの API 向け
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {}
@ApiClass(resource = "boards")
class TicTacToeBoards extends TicTacToeBase { … }
@ApiClass(resource = "scores")
class TicTacToeScores extends TicTacToeBase { … }
同じ API での異なるバージョン テスト向け
@Api(name = "tictactoe", version = "v1")
class TicTacToe {
protected Foo someMethod() {
// Do something real;
}
public Foo getFoo() { … }
}
@Api(version="v1test")
class TicTacToeTest extends TicTacToe {
protected Foo someMethod() {
// Stub out real action;
}
}
someMethod
では、前もって定義されたレスポンスを返したり、副作用を伴う呼び出しを回避したり、ネットワークまたはデータストアのリクエストをスキップしたりできます。
web.xml
へのクラスの追加
クラスにアノテーションを付けたら、それらを web.xml
ファイルに追加する必要があります。次の例は、単一のクラスを示しています。
複数のクラスを追加するには:
<param-value>com.example.skeleton.MyApi</param-value>
は、独自の API クラス名に置き換えます。この同じ
<param-value>
フィールド内に、カンマで区切られた各クラスを追加します。次に例を示します。<param-value>com.example-company.example-api.Hello,com.example-company.example-api.Goodbye</param-value>